ai-database 2.0.1 → 2.1.1
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.
- package/CHANGELOG.md +43 -0
- package/dist/actions.d.ts +247 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +260 -0
- package/dist/actions.js.map +1 -0
- package/dist/ai-promise-db.d.ts +34 -2
- package/dist/ai-promise-db.d.ts.map +1 -1
- package/dist/ai-promise-db.js +511 -66
- package/dist/ai-promise-db.js.map +1 -1
- package/dist/constants.d.ts +16 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -0
- package/dist/events.d.ts +153 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +154 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/memory-provider.d.ts +144 -2
- package/dist/memory-provider.d.ts.map +1 -1
- package/dist/memory-provider.js +569 -13
- package/dist/memory-provider.js.map +1 -1
- package/dist/schema/cascade.d.ts +96 -0
- package/dist/schema/cascade.d.ts.map +1 -0
- package/dist/schema/cascade.js +528 -0
- package/dist/schema/cascade.js.map +1 -0
- package/dist/schema/index.d.ts +197 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +1211 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/parse.d.ts +225 -0
- package/dist/schema/parse.d.ts.map +1 -0
- package/dist/schema/parse.js +732 -0
- package/dist/schema/parse.js.map +1 -0
- package/dist/schema/provider.d.ts +176 -0
- package/dist/schema/provider.d.ts.map +1 -0
- package/dist/schema/provider.js +258 -0
- package/dist/schema/provider.js.map +1 -0
- package/dist/schema/resolve.d.ts +87 -0
- package/dist/schema/resolve.d.ts.map +1 -0
- package/dist/schema/resolve.js +474 -0
- package/dist/schema/resolve.js.map +1 -0
- package/dist/schema/semantic.d.ts +53 -0
- package/dist/schema/semantic.d.ts.map +1 -0
- package/dist/schema/semantic.js +247 -0
- package/dist/schema/semantic.js.map +1 -0
- package/dist/schema/types.d.ts +528 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +9 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/schema.d.ts +24 -867
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +41 -1124
- package/dist/schema.js.map +1 -1
- package/dist/semantic.d.ts +175 -0
- package/dist/semantic.d.ts.map +1 -0
- package/dist/semantic.js +338 -0
- package/dist/semantic.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +13 -4
- package/.turbo/turbo-build.log +0 -5
- package/TESTING.md +0 -410
- package/TEST_SUMMARY.md +0 -250
- package/TODO.md +0 -128
- package/src/ai-promise-db.ts +0 -1243
- package/src/authorization.ts +0 -1102
- package/src/durable-clickhouse.ts +0 -596
- package/src/durable-promise.ts +0 -582
- package/src/execution-queue.ts +0 -608
- package/src/index.test.ts +0 -868
- package/src/index.ts +0 -337
- package/src/linguistic.ts +0 -404
- package/src/memory-provider.test.ts +0 -1036
- package/src/memory-provider.ts +0 -1119
- package/src/schema.test.ts +0 -1254
- package/src/schema.ts +0 -2296
- package/src/tests.ts +0 -725
- package/src/types.ts +0 -1177
- package/test/README.md +0 -153
- package/test/edge-cases.test.ts +0 -646
- package/test/provider-resolution.test.ts +0 -402
- package/tsconfig.json +0 -9
- package/vitest.config.ts +0 -19
package/src/linguistic.ts
DELETED
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Linguistic Helpers
|
|
3
|
-
*
|
|
4
|
-
* Utilities for verb conjugation, noun pluralization, and linguistic inference.
|
|
5
|
-
* Used for auto-generating forms, events, and semantic metadata.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Verbs, type Noun, type Verb, type TypeMeta } from './types.js'
|
|
11
|
-
|
|
12
|
-
// =============================================================================
|
|
13
|
-
// Internal Helpers
|
|
14
|
-
// =============================================================================
|
|
15
|
-
|
|
16
|
-
function capitalize(s: string): string {
|
|
17
|
-
return s.charAt(0).toUpperCase() + s.slice(1)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function preserveCase(original: string, replacement: string): string {
|
|
21
|
-
if (original[0] === original[0]?.toUpperCase()) {
|
|
22
|
-
return capitalize(replacement)
|
|
23
|
-
}
|
|
24
|
-
return replacement
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function isVowel(char: string | undefined): boolean {
|
|
28
|
-
return char ? 'aeiou'.includes(char.toLowerCase()) : false
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function splitCamelCase(s: string): string[] {
|
|
32
|
-
return s.replace(/([a-z])([A-Z])/g, '$1 $2').split(' ')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Check if we should double the final consonant (CVC pattern) */
|
|
36
|
-
function shouldDoubleConsonant(verb: string): boolean {
|
|
37
|
-
if (verb.length < 2) return false
|
|
38
|
-
const last = verb[verb.length - 1]!
|
|
39
|
-
const secondLast = verb[verb.length - 2]!
|
|
40
|
-
// Don't double w, x, y
|
|
41
|
-
if ('wxy'.includes(last)) return false
|
|
42
|
-
// Must end in consonant preceded by vowel
|
|
43
|
-
if (isVowel(last) || !isVowel(secondLast)) return false
|
|
44
|
-
// Common verbs that double the final consonant
|
|
45
|
-
const doublingVerbs = ['submit', 'commit', 'permit', 'omit', 'admit', 'emit', 'transmit', 'refer', 'prefer', 'defer', 'occur', 'recur', 'begin', 'stop', 'drop', 'shop', 'plan', 'scan', 'ban', 'run', 'gun', 'stun', 'cut', 'shut', 'hit', 'sit', 'fit', 'spit', 'quit', 'knit', 'get', 'set', 'pet', 'wet', 'bet', 'let', 'put', 'drag', 'brag', 'flag', 'tag', 'bag', 'nag', 'wag', 'hug', 'bug', 'mug', 'tug', 'rub', 'scrub', 'grab', 'stab', 'rob', 'sob', 'throb', 'nod', 'prod', 'plod', 'plot', 'rot', 'blot', 'spot', 'knot', 'trot', 'chat', 'pat', 'bat', 'mat', 'rat', 'slap', 'clap', 'flap', 'tap', 'wrap', 'snap', 'trap', 'cap', 'map', 'nap', 'zap', 'tip', 'sip', 'dip', 'rip', 'zip', 'slip', 'trip', 'drip', 'chip', 'clip', 'flip', 'grip', 'ship', 'skip', 'whip', 'strip', 'equip', 'hop', 'pop', 'mop', 'cop', 'chop', 'crop', 'prop', 'flop', 'swim', 'trim', 'slim', 'skim', 'dim', 'rim', 'brim', 'grim', 'hem', 'stem', 'jam', 'cram', 'ram', 'slam', 'dam', 'ham', 'scam', 'spam', 'tram', 'hum', 'drum', 'strum', 'sum', 'gum', 'chum', 'plum']
|
|
46
|
-
// Short words (3 letters) almost always double
|
|
47
|
-
if (verb.length <= 3) return true
|
|
48
|
-
// Check if verb matches any known doubling pattern
|
|
49
|
-
return doublingVerbs.some(v => verb === v || verb.endsWith(v))
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Convert verb to past participle (create → created, publish → published) */
|
|
53
|
-
function toPastParticiple(verb: string): string {
|
|
54
|
-
if (verb.endsWith('e')) return verb + 'd'
|
|
55
|
-
if (verb.endsWith('y') && !isVowel(verb[verb.length - 2])) {
|
|
56
|
-
return verb.slice(0, -1) + 'ied'
|
|
57
|
-
}
|
|
58
|
-
if (shouldDoubleConsonant(verb)) {
|
|
59
|
-
return verb + verb[verb.length - 1] + 'ed'
|
|
60
|
-
}
|
|
61
|
-
return verb + 'ed'
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Convert verb to actor noun (create → creator, publish → publisher) */
|
|
65
|
-
function toActor(verb: string): string {
|
|
66
|
-
if (verb.endsWith('e')) return verb + 'r'
|
|
67
|
-
if (verb.endsWith('y') && !isVowel(verb[verb.length - 2])) {
|
|
68
|
-
return verb.slice(0, -1) + 'ier'
|
|
69
|
-
}
|
|
70
|
-
if (shouldDoubleConsonant(verb)) {
|
|
71
|
-
return verb + verb[verb.length - 1] + 'er'
|
|
72
|
-
}
|
|
73
|
-
return verb + 'er'
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Convert verb to present 3rd person (create → creates, publish → publishes) */
|
|
77
|
-
function toPresent(verb: string): string {
|
|
78
|
-
if (verb.endsWith('y') && !isVowel(verb[verb.length - 2])) {
|
|
79
|
-
return verb.slice(0, -1) + 'ies'
|
|
80
|
-
}
|
|
81
|
-
if (verb.endsWith('s') || verb.endsWith('x') || verb.endsWith('z') ||
|
|
82
|
-
verb.endsWith('ch') || verb.endsWith('sh')) {
|
|
83
|
-
return verb + 'es'
|
|
84
|
-
}
|
|
85
|
-
return verb + 's'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Convert verb to gerund (create → creating, publish → publishing) */
|
|
89
|
-
function toGerund(verb: string): string {
|
|
90
|
-
if (verb.endsWith('ie')) return verb.slice(0, -2) + 'ying'
|
|
91
|
-
if (verb.endsWith('e') && !verb.endsWith('ee')) return verb.slice(0, -1) + 'ing'
|
|
92
|
-
if (shouldDoubleConsonant(verb)) {
|
|
93
|
-
return verb + verb[verb.length - 1] + 'ing'
|
|
94
|
-
}
|
|
95
|
-
return verb + 'ing'
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Convert verb to result noun (create → creation, publish → publication) */
|
|
99
|
-
function toResult(verb: string): string {
|
|
100
|
-
// Common -ate → -ation
|
|
101
|
-
if (verb.endsWith('ate')) return verb.slice(0, -1) + 'ion'
|
|
102
|
-
// Common -ify → -ification
|
|
103
|
-
if (verb.endsWith('ify')) return verb.slice(0, -1) + 'ication'
|
|
104
|
-
// Common -ize → -ization
|
|
105
|
-
if (verb.endsWith('ize')) return verb.slice(0, -1) + 'ation'
|
|
106
|
-
// Common -e → -ion (but not always correct)
|
|
107
|
-
if (verb.endsWith('e')) return verb.slice(0, -1) + 'ion'
|
|
108
|
-
// Default: just add -ion
|
|
109
|
-
return verb + 'ion'
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// =============================================================================
|
|
113
|
-
// Public API
|
|
114
|
-
// =============================================================================
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Auto-conjugate a verb from just the base form
|
|
118
|
-
*
|
|
119
|
-
* Given just "publish", generates all forms:
|
|
120
|
-
* - actor: publisher
|
|
121
|
-
* - act: publishes
|
|
122
|
-
* - activity: publishing
|
|
123
|
-
* - result: publication
|
|
124
|
-
* - reverse: { at: publishedAt, by: publishedBy, ... }
|
|
125
|
-
*
|
|
126
|
-
* @example
|
|
127
|
-
* ```ts
|
|
128
|
-
* conjugate('publish')
|
|
129
|
-
* // => { action: 'publish', actor: 'publisher', act: 'publishes', activity: 'publishing', ... }
|
|
130
|
-
*
|
|
131
|
-
* conjugate('create')
|
|
132
|
-
* // => { action: 'create', actor: 'creator', act: 'creates', activity: 'creating', ... }
|
|
133
|
-
* ```
|
|
134
|
-
*/
|
|
135
|
-
export function conjugate(action: string): Verb {
|
|
136
|
-
// Check if it's a known verb first
|
|
137
|
-
if (action in Verbs) {
|
|
138
|
-
return Verbs[action as keyof typeof Verbs]
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const base = action.toLowerCase()
|
|
142
|
-
const pastParticiple = toPastParticiple(base)
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
action: base,
|
|
146
|
-
actor: toActor(base),
|
|
147
|
-
act: toPresent(base),
|
|
148
|
-
activity: toGerund(base),
|
|
149
|
-
result: toResult(base),
|
|
150
|
-
reverse: {
|
|
151
|
-
at: `${pastParticiple}At`,
|
|
152
|
-
by: `${pastParticiple}By`,
|
|
153
|
-
in: `${pastParticiple}In`,
|
|
154
|
-
for: `${pastParticiple}For`,
|
|
155
|
-
},
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Auto-pluralize a noun
|
|
161
|
-
*
|
|
162
|
-
* @example
|
|
163
|
-
* ```ts
|
|
164
|
-
* pluralize('post') // => 'posts'
|
|
165
|
-
* pluralize('category') // => 'categories'
|
|
166
|
-
* pluralize('person') // => 'people'
|
|
167
|
-
* pluralize('child') // => 'children'
|
|
168
|
-
* ```
|
|
169
|
-
*/
|
|
170
|
-
export function pluralize(singular: string): string {
|
|
171
|
-
const lower = singular.toLowerCase()
|
|
172
|
-
|
|
173
|
-
// Irregular plurals
|
|
174
|
-
const irregulars: Record<string, string> = {
|
|
175
|
-
person: 'people',
|
|
176
|
-
child: 'children',
|
|
177
|
-
man: 'men',
|
|
178
|
-
woman: 'women',
|
|
179
|
-
foot: 'feet',
|
|
180
|
-
tooth: 'teeth',
|
|
181
|
-
goose: 'geese',
|
|
182
|
-
mouse: 'mice',
|
|
183
|
-
ox: 'oxen',
|
|
184
|
-
leaf: 'leaves',
|
|
185
|
-
life: 'lives',
|
|
186
|
-
knife: 'knives',
|
|
187
|
-
wife: 'wives',
|
|
188
|
-
half: 'halves',
|
|
189
|
-
self: 'selves',
|
|
190
|
-
calf: 'calves',
|
|
191
|
-
analysis: 'analyses',
|
|
192
|
-
crisis: 'crises',
|
|
193
|
-
thesis: 'theses',
|
|
194
|
-
datum: 'data',
|
|
195
|
-
medium: 'media',
|
|
196
|
-
criterion: 'criteria',
|
|
197
|
-
phenomenon: 'phenomena',
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (irregulars[lower]) {
|
|
201
|
-
return preserveCase(singular, irregulars[lower])
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Rules for regular plurals
|
|
205
|
-
if (lower.endsWith('y') && !isVowel(lower[lower.length - 2])) {
|
|
206
|
-
return singular.slice(0, -1) + 'ies'
|
|
207
|
-
}
|
|
208
|
-
// Words ending in z that double: quiz → quizzes, fez → fezzes
|
|
209
|
-
if (lower.endsWith('z') && !lower.endsWith('zz')) {
|
|
210
|
-
return singular + 'zes'
|
|
211
|
-
}
|
|
212
|
-
if (lower.endsWith('s') || lower.endsWith('x') || lower.endsWith('zz') ||
|
|
213
|
-
lower.endsWith('ch') || lower.endsWith('sh')) {
|
|
214
|
-
return singular + 'es'
|
|
215
|
-
}
|
|
216
|
-
if (lower.endsWith('f')) {
|
|
217
|
-
return singular.slice(0, -1) + 'ves'
|
|
218
|
-
}
|
|
219
|
-
if (lower.endsWith('fe')) {
|
|
220
|
-
return singular.slice(0, -2) + 'ves'
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return singular + 's'
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Auto-singularize a noun (reverse of pluralize)
|
|
228
|
-
*
|
|
229
|
-
* @example
|
|
230
|
-
* ```ts
|
|
231
|
-
* singularize('posts') // => 'post'
|
|
232
|
-
* singularize('categories') // => 'category'
|
|
233
|
-
* singularize('people') // => 'person'
|
|
234
|
-
* ```
|
|
235
|
-
*/
|
|
236
|
-
export function singularize(plural: string): string {
|
|
237
|
-
const lower = plural.toLowerCase()
|
|
238
|
-
|
|
239
|
-
// Irregular singulars
|
|
240
|
-
const irregulars: Record<string, string> = {
|
|
241
|
-
people: 'person',
|
|
242
|
-
children: 'child',
|
|
243
|
-
men: 'man',
|
|
244
|
-
women: 'woman',
|
|
245
|
-
feet: 'foot',
|
|
246
|
-
teeth: 'tooth',
|
|
247
|
-
geese: 'goose',
|
|
248
|
-
mice: 'mouse',
|
|
249
|
-
oxen: 'ox',
|
|
250
|
-
leaves: 'leaf',
|
|
251
|
-
lives: 'life',
|
|
252
|
-
knives: 'knife',
|
|
253
|
-
wives: 'wife',
|
|
254
|
-
halves: 'half',
|
|
255
|
-
selves: 'self',
|
|
256
|
-
calves: 'calf',
|
|
257
|
-
analyses: 'analysis',
|
|
258
|
-
crises: 'crisis',
|
|
259
|
-
theses: 'thesis',
|
|
260
|
-
data: 'datum',
|
|
261
|
-
media: 'medium',
|
|
262
|
-
criteria: 'criterion',
|
|
263
|
-
phenomena: 'phenomenon',
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (irregulars[lower]) {
|
|
267
|
-
return preserveCase(plural, irregulars[lower])
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Rules for regular singulars
|
|
271
|
-
if (lower.endsWith('ies')) {
|
|
272
|
-
return plural.slice(0, -3) + 'y'
|
|
273
|
-
}
|
|
274
|
-
if (lower.endsWith('ves')) {
|
|
275
|
-
return plural.slice(0, -3) + 'f'
|
|
276
|
-
}
|
|
277
|
-
if (lower.endsWith('es') && (
|
|
278
|
-
lower.endsWith('sses') || lower.endsWith('xes') || lower.endsWith('zes') ||
|
|
279
|
-
lower.endsWith('ches') || lower.endsWith('shes')
|
|
280
|
-
)) {
|
|
281
|
-
return plural.slice(0, -2)
|
|
282
|
-
}
|
|
283
|
-
if (lower.endsWith('s') && !lower.endsWith('ss')) {
|
|
284
|
-
return plural.slice(0, -1)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return plural
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Infer a complete Noun from just a type name
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```ts
|
|
295
|
-
* inferNoun('BlogPost')
|
|
296
|
-
* // => { singular: 'blog post', plural: 'blog posts', ... }
|
|
297
|
-
*
|
|
298
|
-
* inferNoun('Category')
|
|
299
|
-
* // => { singular: 'category', plural: 'categories', ... }
|
|
300
|
-
* ```
|
|
301
|
-
*/
|
|
302
|
-
export function inferNoun(typeName: string): Noun {
|
|
303
|
-
const words = splitCamelCase(typeName)
|
|
304
|
-
const singular = words.join(' ').toLowerCase()
|
|
305
|
-
const plural = words.slice(0, -1).concat(pluralize(words[words.length - 1]!)).join(' ').toLowerCase()
|
|
306
|
-
|
|
307
|
-
return {
|
|
308
|
-
singular,
|
|
309
|
-
plural,
|
|
310
|
-
actions: ['create', 'update', 'delete'],
|
|
311
|
-
events: ['created', 'updated', 'deleted'],
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Create TypeMeta from a type name - all linguistic forms auto-inferred
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```ts
|
|
320
|
-
* const meta = createTypeMeta('BlogPost')
|
|
321
|
-
* meta.singular // 'blog post'
|
|
322
|
-
* meta.plural // 'blog posts'
|
|
323
|
-
* meta.slug // 'blog-post'
|
|
324
|
-
* meta.created // 'BlogPost.created'
|
|
325
|
-
* meta.createdAt // 'createdAt'
|
|
326
|
-
* meta.creator // 'creator'
|
|
327
|
-
* ```
|
|
328
|
-
*/
|
|
329
|
-
export function createTypeMeta(typeName: string): TypeMeta {
|
|
330
|
-
const noun = inferNoun(typeName)
|
|
331
|
-
const slug = noun.singular.replace(/\s+/g, '-')
|
|
332
|
-
const slugPlural = noun.plural.replace(/\s+/g, '-')
|
|
333
|
-
|
|
334
|
-
return {
|
|
335
|
-
name: typeName,
|
|
336
|
-
singular: noun.singular,
|
|
337
|
-
plural: noun.plural,
|
|
338
|
-
slug,
|
|
339
|
-
slugPlural,
|
|
340
|
-
|
|
341
|
-
// From Verbs.create
|
|
342
|
-
creator: 'creator',
|
|
343
|
-
createdAt: 'createdAt',
|
|
344
|
-
createdBy: 'createdBy',
|
|
345
|
-
updatedAt: 'updatedAt',
|
|
346
|
-
updatedBy: 'updatedBy',
|
|
347
|
-
|
|
348
|
-
// Event types
|
|
349
|
-
created: `${typeName}.created`,
|
|
350
|
-
updated: `${typeName}.updated`,
|
|
351
|
-
deleted: `${typeName}.deleted`,
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/** Cache of TypeMeta by type name */
|
|
356
|
-
const typeMetaCache = new Map<string, TypeMeta>()
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Get or create TypeMeta for a type name (cached)
|
|
360
|
-
*/
|
|
361
|
-
export function getTypeMeta(typeName: string): TypeMeta {
|
|
362
|
-
let meta = typeMetaCache.get(typeName)
|
|
363
|
-
if (!meta) {
|
|
364
|
-
meta = createTypeMeta(typeName)
|
|
365
|
-
typeMetaCache.set(typeName, meta)
|
|
366
|
-
}
|
|
367
|
-
return meta
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Type proxy - provides dynamic access to type metadata
|
|
372
|
-
*
|
|
373
|
-
* @example
|
|
374
|
-
* ```ts
|
|
375
|
-
* const Post = Type('Post')
|
|
376
|
-
* Post.singular // 'post'
|
|
377
|
-
* Post.plural // 'posts'
|
|
378
|
-
* Post.created // 'Post.created'
|
|
379
|
-
*
|
|
380
|
-
* // In event handlers:
|
|
381
|
-
* on.create(thing => {
|
|
382
|
-
* console.log(thing.$type.plural) // 'posts'
|
|
383
|
-
* })
|
|
384
|
-
* ```
|
|
385
|
-
*/
|
|
386
|
-
export function Type(name: string): TypeMeta {
|
|
387
|
-
return getTypeMeta(name)
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Get reverse property names for a verb action
|
|
392
|
-
*
|
|
393
|
-
* @example
|
|
394
|
-
* ```ts
|
|
395
|
-
* getVerbFields('create')
|
|
396
|
-
* // => { at: 'createdAt', by: 'createdBy', in: 'createdIn', for: 'createdFor' }
|
|
397
|
-
*
|
|
398
|
-
* getVerbFields('publish')
|
|
399
|
-
* // => { at: 'publishedAt', by: 'publishedBy' }
|
|
400
|
-
* ```
|
|
401
|
-
*/
|
|
402
|
-
export function getVerbFields(action: keyof typeof Verbs): Record<string, string> {
|
|
403
|
-
return Verbs[action]?.reverse ?? {}
|
|
404
|
-
}
|