-
Notifications
You must be signed in to change notification settings - Fork 301
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor from schema to use centralized event factories
- Loading branch information
Showing
22 changed files
with
1,659 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { telemetryRecorder } from '../singleton' | ||
import { type Unmapped, event, fallbackValue, pickDefined } from './internal' | ||
|
||
export const events = [ | ||
event( | ||
'cody.at-mention/selected', | ||
({ map, maps, action, feature }) => | ||
( | ||
source: Unmapped<typeof maps.source, true>, | ||
provider: Unmapped<typeof maps.provider> | undefined | null = undefined, | ||
providerMetadata: { id?: string } | undefined = undefined | ||
) => { | ||
telemetryRecorder.recordEvent(feature, action, { | ||
metadata: pickDefined({ | ||
source: map.source(source), | ||
provider: | ||
provider !== undefined ? map.provider(provider ?? fallbackValue) : undefined, | ||
}), | ||
privateMetadata: { source, provider, providerMetadata }, | ||
billingMetadata: { | ||
product: 'cody', | ||
category: 'core', | ||
}, | ||
}) | ||
}, | ||
{ | ||
source: { chat: 1 }, | ||
provider: { | ||
[fallbackValue]: 0, | ||
file: 1, | ||
symbol: 2, | ||
repo: 3, | ||
remoteRepo: 4, | ||
openctx: 5, | ||
}, | ||
} | ||
), | ||
] as const |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { events as atMentionEvents } from './atMention' | ||
|
||
export const events = objectFromPairs([...atMentionEvents]) | ||
|
||
// Function to create an object from pairs with correct typing | ||
type FromPairs<T extends readonly (readonly [PropertyKey, any])[]> = { | ||
[K in T[number][0]]: Extract<T[number], readonly [K, any]>[1] | ||
} | ||
|
||
function objectFromPairs<T extends readonly (readonly [PropertyKey, any])[]>(pairs: T): FromPairs<T> { | ||
return Object.fromEntries(pairs) as FromPairs<T> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import type { LiteralUnion } from 'type-fest' | ||
declare const fallbackVariant: unique symbol | ||
// we disguise the fallbackValue as a tagged string so that it can be exported as a type | ||
export const fallbackValue = '__fallback__' as const | ||
export type MapperInput = { [key: string]: number } & ( | ||
| { [fallbackValue]: number } | ||
| { [fallbackValue]?: never } | ||
) | ||
|
||
export type MapperInputs = Record<string, MapperInput> | ||
|
||
type ObjWithFallback<T extends Record<string, number>> = T & { | ||
[fallbackValue]?: number | ||
} | ||
type KeyOfOmitFallback<T> = T extends ObjWithFallback<infer U> ? keyof U : never | ||
|
||
type HasFallback<M extends MapperInput> = M extends { [fallbackValue]: infer V } | ||
? V extends number | ||
? true | ||
: false | ||
: false | ||
export type MapperFn<M extends MapperInput> = HasFallback<M> extends true | ||
? (v: LiteralUnion<KeyOfOmitFallback<M>, string>) => number | ||
: < | ||
V extends LiteralUnion<KeyOfOmitFallback<M>, string> = LiteralUnion< | ||
KeyOfOmitFallback<M>, | ||
string | ||
>, | ||
>( | ||
v: V | ||
) => V extends KeyOfOmitFallback<M> ? number : null | ||
|
||
export type MapperFns<M extends MapperInputs> = { | ||
[K in keyof M]: MapperFn<M[K]> | ||
} | ||
export type Unmapped<M extends MapperInput, Strict extends boolean = false> = Strict extends true | ||
? KeyOfOmitFallback<M> | ||
: LiteralUnion<KeyOfOmitFallback<M>, string> | ||
|
||
type SplitSignature<S extends string, D extends string = '/'> = string extends S | ||
? string[] | ||
: S extends '' | ||
? [] | ||
: S extends `${infer T}${D}${infer U}` | ||
? [T, ...SplitSignature<U, D>] | ||
: [S] | ||
|
||
function splitSignature<const S extends string>(sig: S): SplitSignature<S, '/'> { | ||
return sig.split('/') as SplitSignature<S> | ||
} | ||
|
||
export function event< | ||
Signature extends `${string}/${string}`, | ||
M extends MapperInputs, | ||
Args extends readonly unknown[], | ||
>( | ||
featureAction: Signature, | ||
builder: (ctx: { | ||
maps: M | ||
map: MapperFns<M> | ||
feature: SplitSignature<Signature>[0] | ||
action: SplitSignature<Signature>[1] | ||
}) => (...args: Args) => void, | ||
maps: M | ||
) { | ||
const [feature, action] = splitSignature(featureAction) | ||
//TODO: Make type-safe | ||
const map = new Proxy(maps, { | ||
get(target, p) { | ||
const mapping = target[p as keyof M] | ||
return (v: any) => mapping[v] ?? mapping[fallbackValue] ?? null | ||
}, | ||
}) as unknown as MapperFns<M> | ||
const ctx = { | ||
map, | ||
maps, | ||
featureAction, | ||
feature, | ||
action, | ||
} | ||
const out = { | ||
ctx, | ||
record: builder(ctx), | ||
} as const | ||
return [featureAction, out] as const | ||
} | ||
|
||
type PickDefined<T> = { | ||
[K in keyof T]-?: T[K] extends undefined ? never : T[K] extends infer U | undefined ? U : T[K] | ||
} | ||
|
||
/** | ||
* Only omit undefined keys. Null keys are not omitted so that the mappers still | ||
* give type errors in case no default value is provided | ||
*/ | ||
export function pickDefined<T>(obj: T): PickDefined<T> { | ||
const result: any = {} | ||
for (const key in obj) { | ||
const value = obj[key] | ||
if (value !== undefined) { | ||
result[key] = value | ||
} | ||
} | ||
return result | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.