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