{"version":3,"sources":["../src/Errors/FeathersFactoryError.ts","../src/TemplateContext.ts","../src/FactoryTemplate.ts","../src/Factory.ts","../src/GlobalFactories.ts"],"sourcesContent":["export default class FeathersFactoryError extends Error {}\nexport class FeathersServiceNotDefined extends FeathersFactoryError {}\n","import Clues from 'clues';\nimport type { Get, Paths } from 'type-fest';\nimport type { FactoryTemplate } from './FactoryTemplate';\n\n/**\n * Factory Template context.\n * Provides access to the current generation context.\n *\n * The `this` type within your template's generator functions.\n */\nexport class TemplateContext<TTemplate, TContext extends TemplateContext<TTemplate> = any> {\n    /**\n     * Internal state for the getter machine.\n     * The structure of this field can be unexpected unless explicitly accessed\n     * through the {@link this.get} method.\n     * @private\n     */\n    public readonly _state: ContextState<TTemplate>;\n    \n    constructor(protected readonly template: FactoryTemplate<TTemplate, TContext>) {\n        this._state = Object.create(this);\n        \n        const entries = Object.entries(this.template._schema).map(([key, value]) => {\n            return [key, this.wrapTemplateField(value)]\n        })\n        \n        Object.assign(this._state, Object.fromEntries(entries));\n    }\n    \n    /**\n     * Resolve the value of a template field within the current generator\n     * context. Fields are only resolved once per generator context.\n     *\n     * This ensures that you can safely reference the same field multiple times\n     * within the same generation context and from different fields.\n     *\n     * @example\n     * template = ({\n     *     firstName: () => faker.person.firstName(),\n     *     lastName: () => faker.person.lastName(),\n     *\n     *     fullName: () => `${this.get('firstName')} ${this.get('lastName')}`,\n     *     // -> John Doe\n     *\n     *     // Functions are only called once, then cached to ensure consistent\n     *     // results within the same generation context.\n     *     email: () => `${this.get('firstName')}.${this.get('lastName')}@example.com`\n     *     // -> John.Doe@example.com,\n     * })\n     *\n     */\n    public get<TKey extends Paths<TTemplate> & string>(key: TKey): ContextFieldOutcome<Get<TTemplate, TKey>> {\n        return Clues(this._state, key as string, { CONTEXT: this });\n    }\n    \n    /**\n     * Run the generator function for a given field. This will not cache the\n     * result within the current context. Meaning you can call it multiple times\n     * within the same generation context and it will always return a new value.\n     *\n     * This is useful if you want to extend the result of a field from within\n     * another field. Do keep in mind that you might want to use it sparingly\n     * in case the field has side-effects. E.g. creating new records in the\n     * database.\n     *\n     * @example\n     * template = ({\n     *     firstName: () => faker.person.firstName(),\n     *     lastName: () => faker.person.lastName(),\n     *\n     *     fullName: () => `${this.get('firstName')} ${this.get('lastName')}`,\n     *     // -> John Doe\n     *\n     *     family: () => [\n     *         this.call('fullName'), // -> <New random name>\n     *         this.call('fullName'), // -> <New random name>\n     *\n     *         this.get('fullName'), // -> John Doe\n     *     ]\n     */\n    public call<TKey extends Paths<TTemplate> & string>(key: TKey): ContextFieldOutcome<Get<TTemplate, TKey>> {\n        const freshContext = new TemplateContext(this.template);\n        \n        return freshContext.get(key);\n    }\n    \n    /**\n     * Wrap any template functions around an array to indicate to Clues.js\n     * what parameters are expected. Which is just this class instance.\n     *\n     * Enables use of the context parameter in arrow functions.\n     */\n    protected wrapTemplateField(field: unknown) {\n        if (!this.shouldWrap(field)) {\n            return field;\n        }\n        return ['CONTEXT', function(this: unknown, CONTEXT: TemplateContext<TTemplate>) {\n            return field.apply(this, [CONTEXT])\n        }]\n    }\n    \n    /**\n     * Check whether the provided field is a function we should wrap to help\n     * Clues.js resolve input types.\n     */\n    protected shouldWrap(field: unknown): field is Function {\n        if (typeof field !== 'function') {\n            return false;\n        }\n        if (Object.getOwnPropertyDescriptor(field, 'prototype')?.writable === false) {\n            return false;\n        }\n        return true;\n    }\n    \n    /**\n     * Attempt to resolve the current context state.\n     * Used primarily for testing. The internal state does change during\n     * resolve and could yield unexpected results.\n     * @private\n     */\n    public async _resolveState() {\n        const result = Object.keys(this._state).map(async (key) => {\n            return [key, await this.get(key as any)]\n        });\n        return Object.fromEntries(await Promise.all(result));\n    };\n}\n\n/**\n * Resolver state. May contain some partially resolved template fields.\n */\ntype ContextState<TTemplate> = {\n    [key in keyof TTemplate]: ContextField<TTemplate[key]>;\n}\n\n/**\n * Contextualized FactoryTemplate fields.\n * When resolving some fields will get converted to promises,\n * some immediately to their resulting value, etc.\n *\n * Todo: Attempt to infer types that will never get converted to a promise or\n *  function. (sync functions, static values, etc.)\n */\ntype ContextField<TType> =\n    | TType\n    | Promise<TType>\n    | (() => Promise<TType> | TType);\n\n/**\n * After resolving a field, it'll either be it's final type or a promise\n * in cases where there's peer dependencies or the field function actually\n * is async.\n */\ntype ContextFieldOutcome<TType> =\n    TType extends ContextField<infer T>\n    ? Promise<T> | T\n    : never;","import { TemplateContext } from './TemplateContext';\n\n/**\n * Factory boilerplate template.\n * Defines the fields that will be generated when factories are called.\n */\nexport class FactoryTemplate<TTemplate, TContext extends TemplateContext<TTemplate> = TemplateContext<TTemplate>> {\n    constructor(public readonly _schema: TemplateSchema<TTemplate, TContext>) {}\n    \n    /**\n     * Run all factory functions in the template and return final result to be\n     * stored in the database.\n     */\n    public resolve(overrides?: TemplateOverrides<TTemplate, TContext>): Promise<TemplateResult<TTemplate>> {\n        const template = this.extend(overrides || {});\n        const context = new TemplateContext(template);\n        \n        return context._resolveState();\n    }\n    \n    public extend<TOverrides>(overrides: ExtendSchema<TTemplate, TOverrides>): ExtendTemplate<TTemplate, TOverrides> {\n        // @ts-expect-error Incompatible types\n        return new FactoryTemplate({\n            ...this._schema,\n            ...overrides,\n        })\n    }\n}\n\n/**\n * Factory Template definition.\n * Defines the fields that will be generated when the factory is called.\n */\nexport type TemplateSchema<TTemplate, TContext = TemplateContext<TTemplate>> = {\n    [key in keyof TTemplate]: TemplateField<TTemplate[key], TContext>;\n} & ThisType<TContext>;\n\n\n/**\n * Factory Template field.\n * Specifies a function to run every time the factory is called. Or a static\n * value that will always remain the same.\n */\ntype TemplateField<\n    TValue = unknown,\n    TContext = unknown,\n> = TValue | Promise<TValue> | ((context: TContext) => TValue | Promise<TValue>);\n\n/**\n * Factory Template result.\n * The raw output of type of the template after resolving all fields.\n */\nexport type TemplateResult<TTemplate> = {\n    [key in keyof TTemplate]: InferFieldType<TTemplate[key]>;\n}\n\n/**\n * Infer the resulting data type of the provided factory template.\n * @example\n * const userTemplate = new FactoryTemplate({\n *     userId: () => 123,\n *     createdAt: () => new Date()\n * })\n *\n * const data: InferOutput<typeof userTemplate>\n *     // -> { userId: number, createdAt: Date }\n */\nexport type InferOutput<TTemplate> = TTemplate extends FactoryTemplate<infer T> ? T : never;\n\n/**\n * Template overrides.\n * Defines the fields that can be overridden before resolving the final\n * template.\n */\nexport type TemplateOverrides<TTemplate, TContext = {}> = {\n    [key in keyof TTemplate]?: TemplateField<InferFieldType<TTemplate[key]>, TContext>;\n} & ThisType<TContext>;\n\n/**\n * Infer the resolved output type of a given template field.\n */\nexport type InferFieldType<T> = T extends TemplateField<infer T> ? T : never;\n\n/**\n * Merge two template definitions to create a new template using one as a base.\n */\nexport type ExtendTemplate<\n    TTemplate,\n    TOverrides,\n    TResult = TTemplate & TOverrides,\n    TMerged = {\n        [key in keyof TResult]: key extends keyof TOverrides\n                                ? TOverrides[key]\n                                : TResult[key];\n    }\n> = FactoryTemplate<TMerged>;\n\n/**\n * Combine a target schema with a baseline schema.\n */\nexport type ExtendSchema<\n    TTemplate,\n    TOverrides,\n    TResult = TTemplate & TOverrides,\n    TMerged = {\n        [key in keyof TResult]: key extends keyof TOverrides\n                                ? TOverrides[key]\n                                : TResult[key];\n    }\n> = TOverrides & ThisType<TemplateContext<TMerged>>;","import { Params } from '@feathersjs/feathers';\nimport { FeathersServiceNotDefined } from './Errors/FeathersFactoryError';\nimport { FactoryTemplate, type TemplateOverrides, type TemplateSchema } from './FactoryTemplate';\nimport type { FactoryCompatibleService } from './ServiceTypes';\n\nexport default class Factory<\n    TSchema,\n    TResult = TSchema,\n    TParams = Params,\n> {\n    protected readonly data: FactoryTemplate<TSchema>;\n    protected readonly params: FactoryTemplate<Params>;\n    \n    /**\n     * Factory constructor.\n     */\n    public constructor(\n        private readonly service: FactoryCompatibleService<TSchema, TResult, TParams>,\n        data: TemplateSchema<TSchema> | FactoryTemplate<TSchema>,\n        defaultParams: TemplateSchema<TParams> = {} as any,\n    ) {\n        if (!service) {\n            throw new FeathersServiceNotDefined('The provided service doesn\\'t appear to exist!');\n        }\n        \n        if (data instanceof FactoryTemplate) {\n            this.data = data;\n        } else {\n            this.data = new FactoryTemplate(data);\n        }\n        \n        this.params = new FactoryTemplate(defaultParams);\n    }\n    \n    /**\n     * Store generated data to the Feathers service.\n     */\n    public async create(\n        data?: TemplateOverrides<TSchema>,\n        params?: TemplateOverrides<TParams>,\n    ): Promise<TResult> {\n        const resolvedData: any = await this.get(data);\n        const resolvedParams = await this.params.resolve(params);\n        \n        return this.service.create(resolvedData, resolvedParams as TParams) as Promise<TResult>;\n    }\n    \n    /**\n     * Quickly populate the database running the factory a number of times.\n     */\n    public createMany(\n        quantity: number,\n        overrides?: TemplateOverrides<TSchema>,\n        params?: TemplateOverrides<TParams>,\n    ): Promise<TResult[]> {\n        const promises: Promise<TResult>[] = [];\n        \n        for (let i = 0; i < quantity; i++) {\n            promises.push(this.create(overrides, params));\n        }\n        \n        return Promise.all(promises);\n    }\n    \n    /**\n     * Just resolve a predefined factory template without inserting it into\n     * the underlying service.\n     *\n     * @param overrides\n     */\n    public get(overrides: TemplateOverrides<TSchema> = {}) {\n        return this.data.resolve(overrides);\n    }\n    \n}\n\n","import { Params } from '@feathersjs/feathers';\nimport Factory from './Factory';\nimport type { TemplateOverrides } from './FactoryTemplate';\nimport type { HasBeenAugmented } from './lib/Utilities';\n\n\n/**\n * We are intentionally leaving this empty here so you can add type\n * declarations for globally accessible factories.\n *\n * @example\n * const MyUserFactory = new Factory(...);\n *\n * declare module 'feathers-factory' {\n *     interface GlobalFactories {\n *          'user-factory': typeof MyUserFactory\n *     }\n * }\n */\nexport interface GlobalFactories {\n\n}\n\n\nexport default new class GlobalFactories {\n\n    /**\n     * Defined factories.\n     */\n    public factories = {} as FactoryRegistry;\n\n    /**\n     * Define a new factory.\n     */\n    public define<\n        TSchema,\n        TResult = TSchema,\n    >(\n        factoryName: FactoryName,\n        factory: Factory<TSchema, TResult>,\n    ) {\n        this.factories[factoryName] = factory;\n    }\n    \n    /**\n     * Retrieve a factory name as defined in the define() method.\n     *\n     * @param name\n     */\n    public getFactory<TName extends FactoryName>(name: TName): GlobalFactory<TName> {\n        const factory = this.factories[name];\n    \n        if (!factory) {\n            throw Error(`Could not locate factory '${name}'. Did you define it?`);\n        }\n        \n        return factory;\n    }\n    \n\n    /**\n     * Run factory, creating entry in Feathers service.\n     *\n     * @param factoryName\n     * @param overrides\n     * @param params\n     */\n    public create<\n        TName extends FactoryName\n    >(factoryName: TName, overrides?: GlobalFactoryOverrides<TName>, params?: Params) {\n        const factory = this.getFactory(factoryName);\n\n        return factory.create(overrides, params);\n    }\n\n    /**\n     * Run a number of factories, creating entries in Feathers service.\n     *\n     * @param quantity\n     * @param factoryName\n     * @param overrides\n     * @param params\n     */\n    public createMany<\n        TName extends FactoryName\n    >(quantity: number, factoryName: TName, overrides?: TemplateOverrides<any>, params?: Params) {\n        const factory = this.getFactory(factoryName);\n        return factory.createMany(quantity, overrides, params);\n    }\n\n    /**\n     * Run factory without creating entry in Feathers service.\n     * Returns resolved data object.\n     *\n     * @param factoryName\n     * @param overrides\n     */\n    public get<\n        TName extends FactoryName\n    >(factoryName: TName, overrides?: TemplateOverrides<TName>) {\n        const factory = this.factories[factoryName];\n\n        if (!factory) {\n            throw Error(`Could not locate factory '${factoryName}'. Did you define it?`);\n        }\n\n        return factory.get(overrides);\n    }\n\n}\n\ntype FactoryName = keyof FactoryRegistry;\ntype GlobalFactory<TName extends FactoryName> = FactoryRegistry[TName];\n\ntype GlobalFactoryOverrides<\n    TName extends FactoryName\n> = GlobalFactory<TName> extends Factory<infer TSchema, infer TResult>\n    ? TemplateOverrides<TSchema>\n    : never;\n\ntype FactoryRegistry = HasBeenAugmented<GlobalFactories> extends true\n                       ? GlobalFactories\n                       : DefaultFactoryRegistry\n\ntype DefaultFactoryRegistry = {\n    [key: string]: Factory<any, any>;\n}\n\n"],"mappings":"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","names":[]}