| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- // prettier-ignore
- import {
- ConfigArg,
- ConfigArgDefinition,
- ConfigurableOperationDefinition,
- LanguageCode,
- LocalizedString,
- Maybe,
- StringFieldOption,
- } from '@vendure/common/lib/generated-types';
- import { ConfigArgType } from '@vendure/common/lib/shared-types';
- import { simpleDeepClone } from '@vendure/common/lib/simple-deep-clone';
- import { RequestContext } from '../api/common/request-context';
- import { DEFAULT_LANGUAGE_CODE } from './constants';
- import { InternalServerError } from './error/errors';
- import { Injector } from './injector';
- import { InjectableStrategy } from './types/injectable-strategy';
- /**
- * @description
- * An array of string values in a given {@link LanguageCode}, used to define human-readable string values.
- *
- * @example
- * ```TypeScript
- * const title: LocalizedStringArray = [
- * { languageCode: LanguageCode.en, value: 'English Title' },
- * { languageCode: LanguageCode.de, value: 'German Title' },
- * { languageCode: LanguageCode.zh, value: 'Chinese Title' },
- * ]
- * ```
- *
- * @docsCategory common
- * @docsPage Configurable Operations
- */
- export type LocalizedStringArray = Array<Omit<LocalizedString, '__typename'>>;
- export interface ConfigArgCommonDef<T extends ConfigArgType> {
- type: T;
- label?: LocalizedStringArray;
- description?: LocalizedStringArray;
- }
- export type WithArgConfig<T> = {
- config?: T;
- };
- export type StringArgConfig = WithArgConfig<{
- options?: Maybe<StringFieldOption[]>;
- }>;
- export type IntArgConfig = WithArgConfig<{
- inputType?: 'default' | 'percentage' | 'money';
- }>;
- export type ConfigArgDef<T extends ConfigArgType> = T extends 'string'
- ? ConfigArgCommonDef<'string'> & StringArgConfig
- : T extends 'int'
- ? ConfigArgCommonDef<'int'> & IntArgConfig
- : ConfigArgCommonDef<T> & WithArgConfig<never>;
- /**
- * @description
- * A object which defines the configurable arguments which may be passed to
- * functions in those classes which implement the {@link ConfigurableOperationDef} interface.
- *
- * @example
- * ```TypeScript
- * {
- * operator: {
- * type: 'string',
- * config: {
- * options: [
- * { value: 'startsWith' },
- * { value: 'endsWith' },
- * { value: 'contains' },
- * { value: 'doesNotContain' },
- * ],
- * },
- * },
- * term: { type: 'string' },
- * }
- * ```
- *
- * @docsCategory common
- * @docsPage Configurable Operations
- */
- export type ConfigArgs<T extends ConfigArgType> = {
- [name: string]: ConfigArgDef<T>;
- };
- // prettier-ignore
- /**
- * Represents the ConfigArgs once they have been coerced into JavaScript values for use
- * in business logic.
- */
- export type ConfigArgValues<T extends ConfigArgs<any>> = {
- [K in keyof T]: T[K] extends ConfigArgDef<'int' | 'float'>
- ? number
- : T[K] extends ConfigArgDef<'datetime'>
- ? Date
- : T[K] extends ConfigArgDef<'boolean'>
- ? boolean
- : T[K] extends ConfigArgDef<'facetValueIds'>
- ? string[]
- : string
- };
- /**
- * @description
- * Common configuration options used when creating a new instance of a
- * {@link ConfigurableOperationDef}.
- *
- * @docsCategory common
- * @docsPage Configurable Operations
- */
- export interface ConfigurableOperationDefOptions<T extends ConfigArgs<ConfigArgType>>
- extends InjectableStrategy {
- /**
- * @description
- * A unique code used to identify this operation.
- */
- code: string;
- /**
- * @description
- * Optional provider-specific arguments which, when specified, are
- * editable in the admin-ui. For example, args could be used to store an API key
- * for a payment provider service.
- *
- * @example
- * ```ts
- * args: {
- * apiKey: { type: 'string' },
- * }
- * ```
- *
- * See {@link ConfigArgs} for available configuration options.
- */
- args: T;
- /**
- * @description
- * A human-readable description for the operation method.
- */
- description: LocalizedStringArray;
- }
- /**
- * @description
- * Defines a ConfigurableOperation, which is a method which can be configured
- * by the Administrator via the Admin API.
- *
- * @docsCategory common
- * @docsPage Configurable Operations
- */
- export class ConfigurableOperationDef<T extends ConfigArgs<ConfigArgType>> {
- get code(): string {
- return this.options.code;
- }
- get args(): T {
- return this.options.args;
- }
- get description(): LocalizedStringArray {
- return this.options.description;
- }
- constructor(protected options: ConfigurableOperationDefOptions<T>) {}
- async init(injector: Injector) {
- if (typeof this.options.init === 'function') {
- await this.options.init(injector);
- }
- }
- async destroy() {
- if (typeof this.options.destroy === 'function') {
- await this.options.destroy();
- }
- }
- }
- /**
- * Convert a ConfigurableOperationDef into a ConfigurableOperation object, typically
- * so that it can be sent via the API.
- */
- export function configurableDefToOperation(
- ctx: RequestContext,
- def: ConfigurableOperationDef<ConfigArgs<any>>,
- ): ConfigurableOperationDefinition {
- return {
- code: def.code,
- description: localizeString(def.description, ctx.languageCode),
- args: Object.entries(def.args).map(
- ([name, arg]) =>
- ({
- name,
- type: arg.type,
- config: localizeConfig(arg, ctx.languageCode),
- label: arg.label && localizeString(arg.label, ctx.languageCode),
- description: arg.description && localizeString(arg.description, ctx.languageCode),
- } as Required<ConfigArgDefinition>),
- ),
- };
- }
- function localizeConfig(
- arg: StringArgConfig | IntArgConfig | WithArgConfig<undefined>,
- languageCode: LanguageCode,
- ): any {
- const { config } = arg;
- if (!config) {
- return config;
- }
- const clone = simpleDeepClone(config);
- const options: Maybe<StringFieldOption[]> = (clone as any).options;
- if (options) {
- for (const option of options) {
- if (option.label) {
- (option as any).label = localizeString(option.label, languageCode);
- }
- }
- }
- return clone;
- }
- function localizeString(stringArray: LocalizedStringArray, languageCode: LanguageCode): string {
- let match = stringArray.find(x => x.languageCode === languageCode);
- if (!match) {
- match = stringArray.find(x => x.languageCode === DEFAULT_LANGUAGE_CODE);
- }
- if (!match) {
- match = stringArray[0];
- }
- return match.value;
- }
- /**
- * Coverts an array of ConfigArgs into a hash object:
- *
- * from:
- * [{ name: 'foo', type: 'string', value: 'bar'}]
- *
- * to:
- * { foo: 'bar' }
- **/
- export function argsArrayToHash<T extends ConfigArgs<any>>(args: ConfigArg[]): ConfigArgValues<T> {
- const output: ConfigArgValues<T> = {} as any;
- for (const arg of args) {
- if (arg && arg.value != null) {
- output[arg.name as keyof ConfigArgValues<T>] = coerceValueToType<T>(arg);
- }
- }
- return output;
- }
- function coerceValueToType<T extends ConfigArgs<any>>(arg: ConfigArg): ConfigArgValues<T>[keyof T] {
- switch (arg.type as ConfigArgType) {
- case 'string':
- return arg.value as any;
- case 'int':
- return Number.parseInt(arg.value || '', 10) as any;
- case 'datetime':
- return Date.parse(arg.value || '') as any;
- case 'boolean':
- return !!(arg.value && (arg.value.toLowerCase() === 'true' || arg.value === '1')) as any;
- case 'facetValueIds':
- try {
- return JSON.parse(arg.value as any);
- } catch (err) {
- throw new InternalServerError(err.message);
- }
- default:
- return (arg.value as string) as any;
- }
- }
|