mirror of
https://github.com/hexastack/hexabot
synced 2025-04-10 15:55:55 +00:00
feat: define getters and setters
This commit is contained in:
parent
8bef5e521b
commit
172a167296
@ -60,12 +60,12 @@ The envelope helpers introduce two key components to streamline outgoing message
|
||||
```typescript
|
||||
// Build a simple text envelope:
|
||||
const env1 = EnvelopeBuilder(OutgoingMessageFormat.text)
|
||||
.text('Hello')
|
||||
.setText('Hello')
|
||||
.build();
|
||||
|
||||
// Append multiple quick replies:
|
||||
const env2 = EnvelopeBuilder(OutgoingMessageFormat.quickReplies)
|
||||
.text('Are you interested?')
|
||||
.setText('Are you interested?')
|
||||
.appendToQuickReplies({
|
||||
content_type: QuickReplyType.text,
|
||||
title: 'Yes',
|
||||
@ -91,8 +91,8 @@ const textEnvelope = envelopeFactory.buildTextEnvelope('Hello, {context.user.nam
|
||||
const quickRepliesEnvelope = envelopeFactory.buildQuickRepliesEnvelope(
|
||||
'Do you want to proceed?',
|
||||
[
|
||||
{ content_type: 'text', title: 'Yes', payload: 'yes' },
|
||||
{ content_type: 'text', title: 'No', payload: 'no' }
|
||||
{ content_type: QuickReplyType.text, title: 'Yes', payload: 'yes' },
|
||||
{ content_type: QuickReplyType.text, title: 'No', payload: 'no' }
|
||||
]
|
||||
);
|
||||
```
|
||||
|
@ -28,7 +28,7 @@ describe('EnvelopeBuilder', () => {
|
||||
stdOutgoingTextEnvelopeSchema,
|
||||
);
|
||||
|
||||
builder.text('Hello');
|
||||
builder.setText('Hello');
|
||||
|
||||
const result = builder.build();
|
||||
expect(result).toEqual({
|
||||
@ -46,9 +46,9 @@ describe('EnvelopeBuilder', () => {
|
||||
stdOutgoingTextEnvelopeSchema,
|
||||
);
|
||||
|
||||
builder.text('Hello world');
|
||||
builder.setText('Hello world');
|
||||
// Retrieve current value with no argument
|
||||
expect(builder.text()).toBe('Hello world');
|
||||
expect(builder.getText()).toBe('Hello world');
|
||||
});
|
||||
|
||||
it('should append items to array fields with appendToX methods', () => {
|
||||
@ -58,7 +58,7 @@ describe('EnvelopeBuilder', () => {
|
||||
stdOutgoingQuickRepliesEnvelopeSchema,
|
||||
);
|
||||
|
||||
builder.text('Choose an option');
|
||||
builder.setText('Choose an option');
|
||||
builder.appendToQuickReplies({
|
||||
content_type: QuickReplyType.text,
|
||||
title: 'Yes',
|
||||
@ -76,8 +76,8 @@ describe('EnvelopeBuilder', () => {
|
||||
message: {
|
||||
text: 'Choose an option',
|
||||
quickReplies: [
|
||||
{ content_type: 'text', title: 'Yes', payload: 'yes' },
|
||||
{ content_type: 'text', title: 'No', payload: 'no' },
|
||||
{ content_type: QuickReplyType.text, title: 'Yes', payload: 'yes' },
|
||||
{ content_type: QuickReplyType.text, title: 'No', payload: 'no' },
|
||||
],
|
||||
},
|
||||
});
|
||||
@ -97,7 +97,7 @@ describe('EnvelopeBuilder', () => {
|
||||
describe('getEnvelopeBuilder', () => {
|
||||
it('should return a builder for text format that passes validation with required field', () => {
|
||||
const builder = getEnvelopeBuilder(OutgoingMessageFormat.text);
|
||||
builder.text('Hello from text envelope!');
|
||||
builder.setText('Hello from text envelope!');
|
||||
|
||||
const envelope = builder.build();
|
||||
expect(envelope.format).toBe(OutgoingMessageFormat.text);
|
||||
@ -106,7 +106,7 @@ describe('getEnvelopeBuilder', () => {
|
||||
|
||||
it('should return a builder for quickReplies format that can append items', () => {
|
||||
const builder = getEnvelopeBuilder(OutgoingMessageFormat.quickReplies);
|
||||
builder.text('Pick an option');
|
||||
builder.setText('Pick an option');
|
||||
builder.appendToQuickReplies({
|
||||
content_type: QuickReplyType.text,
|
||||
title: 'Option A',
|
||||
|
@ -31,8 +31,11 @@ type ArrayKeys<T> = {
|
||||
}[keyof T];
|
||||
|
||||
export type IEnvelopeBuilder<T extends StdOutgoingEnvelope> = {
|
||||
[k in keyof T['message']]-?: ((arg: T['message'][k]) => IEnvelopeBuilder<T>) &
|
||||
(() => T['message'][k]);
|
||||
[K in keyof T['message'] as `set${Capitalize<string & K>}`]-?: (
|
||||
arg: T['message'][K],
|
||||
) => IEnvelopeBuilder<T>;
|
||||
} & {
|
||||
[K in keyof T['message'] as `get${Capitalize<string & K>}`]-?: () => T['message'][K];
|
||||
} & {
|
||||
[K in ArrayKeys<T['message']> as `appendTo${Capitalize<string & K>}`]: (
|
||||
item: NonNullable<T['message'][K]> extends (infer U)[] ? U : never,
|
||||
@ -41,6 +44,21 @@ export type IEnvelopeBuilder<T extends StdOutgoingEnvelope> = {
|
||||
build(): T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts and transforms a property name into a standardized attribute name.
|
||||
*
|
||||
* @param prop - The property name from which to derive the attribute name.
|
||||
* @param prefix - A regular expression that matches the prefix to remove from the property.
|
||||
* @returns The transformed attribute name with its first character in lowercase.
|
||||
*/
|
||||
function getAttributeNameFromProp(prop: string, prefix: RegExp) {
|
||||
// e.g. "appendToButtons" => "Buttons"
|
||||
const rawKey = prop.toString().replace(prefix, '');
|
||||
// e.g. "Buttons" -> "buttons"
|
||||
const messageKey = rawKey.charAt(0).toLowerCase() + rawKey.slice(1);
|
||||
return messageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an envelope object (containing a `format` and a `message` property)
|
||||
* and returns a proxy-based builder interface with chainable setter methods.
|
||||
@ -60,20 +78,20 @@ export type IEnvelopeBuilder<T extends StdOutgoingEnvelope> = {
|
||||
* @example
|
||||
* // Build a simple text envelope:
|
||||
* const env1 = EnvelopeBuilder(OutgoingMessageFormat.text)
|
||||
* .text('Hello')
|
||||
* .setText('Hello')
|
||||
* .build();
|
||||
*
|
||||
* @example
|
||||
* // Build a text envelope with quick replies:
|
||||
* const env2 = EnvelopeBuilder(OutgoingMessageFormat.quickReplies)
|
||||
* .text('Hello')
|
||||
* .quickReplies([])
|
||||
* .setText('Hello')
|
||||
* .setQuickReplies([])
|
||||
* .build();
|
||||
*
|
||||
* @example
|
||||
* // Append multiple quickReplies items:
|
||||
* const env3 = EnvelopeBuilder(OutgoingMessageFormat.quickReplies)
|
||||
* .text('Are you interested?')
|
||||
* .setText('Are you interested?')
|
||||
* .appendToQuickReplies({
|
||||
* content_type: QuickReplyType.text,
|
||||
* title: 'Yes',
|
||||
@ -89,7 +107,7 @@ export type IEnvelopeBuilder<T extends StdOutgoingEnvelope> = {
|
||||
* @example
|
||||
* // Build a system envelope with an outcome:
|
||||
* const env4 = EnvelopeBuilder(OutgoingMessageFormat.system)
|
||||
* .outcome('success')
|
||||
* .setOutcome('success')
|
||||
* .build();
|
||||
*/
|
||||
export function EnvelopeBuilder<T extends StdOutgoingEnvelope>(
|
||||
@ -119,10 +137,7 @@ export function EnvelopeBuilder<T extends StdOutgoingEnvelope>(
|
||||
}
|
||||
|
||||
if (typeof prop === 'string' && prop.startsWith('appendTo')) {
|
||||
// e.g. "appendToButtons" => "Buttons"
|
||||
const rawKey = prop.replace(/^appendTo/, '');
|
||||
// e.g. "Buttons" -> "buttons"
|
||||
const messageKey = rawKey.charAt(0).toLowerCase() + rawKey.slice(1);
|
||||
const messageKey = getAttributeNameFromProp(prop, /^appendTo/);
|
||||
|
||||
return (item: unknown) => {
|
||||
// Initialize the array if needed
|
||||
@ -137,12 +152,16 @@ export function EnvelopeBuilder<T extends StdOutgoingEnvelope>(
|
||||
return (...args: unknown[]): unknown => {
|
||||
// If no arguments passed return current value.
|
||||
if (0 === args.length) {
|
||||
return built.message[prop.toString()];
|
||||
const messageKey = getAttributeNameFromProp(
|
||||
prop.toString(),
|
||||
/^get/,
|
||||
);
|
||||
return built.message[messageKey];
|
||||
}
|
||||
|
||||
const value = args[0];
|
||||
|
||||
built.message[prop.toString()] = value;
|
||||
const messageKey = getAttributeNameFromProp(prop.toString(), /^set/);
|
||||
built.message[messageKey] = value;
|
||||
return builder;
|
||||
};
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
OutgoingMessageFormat,
|
||||
} from '../schemas/types/message';
|
||||
import { ContentOptions } from '../schemas/types/options';
|
||||
import { StdQuickReply } from '../schemas/types/quick-reply';
|
||||
import { QuickReplyType, StdQuickReply } from '../schemas/types/quick-reply';
|
||||
|
||||
import { EnvelopeFactory } from './envelope-factory';
|
||||
|
||||
@ -245,7 +245,7 @@ describe('EnvelopeFactory', () => {
|
||||
} as AttachmentPayload;
|
||||
const quickReplies = [
|
||||
{
|
||||
content_type: 'text',
|
||||
content_type: QuickReplyType.text,
|
||||
title: 'Yes {contact.company_name}',
|
||||
payload: 'do_{context.user.id}',
|
||||
},
|
||||
|
@ -130,7 +130,7 @@ export class EnvelopeFactory {
|
||||
buildTextEnvelope(text: string | string[]): StdOutgoingTextEnvelope {
|
||||
const builder = this.getBuilder(OutgoingMessageFormat.text);
|
||||
const processedText = this.processText(text);
|
||||
return builder.text(processedText).build();
|
||||
return builder.setText(processedText).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,7 +149,7 @@ export class EnvelopeFactory {
|
||||
): StdOutgoingQuickRepliesEnvelope {
|
||||
const builder = this.getBuilder(OutgoingMessageFormat.quickReplies);
|
||||
const processedText = this.processText(text);
|
||||
const envelope = builder.text(processedText);
|
||||
const envelope = builder.setText(processedText);
|
||||
|
||||
quickReplies.forEach((qr) => {
|
||||
envelope.appendToQuickReplies({
|
||||
@ -179,7 +179,7 @@ export class EnvelopeFactory {
|
||||
): StdOutgoingButtonsEnvelope {
|
||||
const builder = this.getBuilder(OutgoingMessageFormat.buttons);
|
||||
const processedText = this.processText(text);
|
||||
const envelope = builder.text(processedText);
|
||||
const envelope = builder.setText(processedText);
|
||||
|
||||
buttons.forEach((btn) => {
|
||||
if (btn.type === ButtonType.postback) {
|
||||
@ -214,7 +214,7 @@ export class EnvelopeFactory {
|
||||
quickReplies: StdQuickReply[] = [],
|
||||
): StdOutgoingAttachmentEnvelope {
|
||||
const builder = this.getBuilder(OutgoingMessageFormat.attachment);
|
||||
const envelope = builder.attachment(attachment);
|
||||
const envelope = builder.setAttachment(attachment);
|
||||
|
||||
quickReplies.forEach((qr) => {
|
||||
envelope.appendToQuickReplies({
|
||||
@ -247,9 +247,9 @@ export class EnvelopeFactory {
|
||||
): StdOutgoingListEnvelope {
|
||||
const builder = this.getBuilder(format);
|
||||
return builder
|
||||
.options(options)
|
||||
.elements(elements)
|
||||
.pagination(pagination)
|
||||
.setOptions(options)
|
||||
.setElements(elements)
|
||||
.setPagination(pagination)
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -268,6 +268,6 @@ export class EnvelopeFactory {
|
||||
data?: unknown,
|
||||
): StdOutgoingSystemEnvelope {
|
||||
const builder = this.getBuilder(OutgoingMessageFormat.system);
|
||||
return builder.outcome(outcome).data(data).build();
|
||||
return builder.setOutcome(outcome).setData(data).build();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user