{"version":3,"sources":["/home/david/projects/open-source/plug-and-play/dist/index.cjs","../src/index.ts","../src/error.ts"],"names":["require","hook"],"mappings":"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","file":"/home/david/projects/open-source/plug-and-play/dist/index.cjs","sourcesContent":[null,"import { is_object_literal, is_object } from \"mixme\";\nimport * as toposort from \"toposort\";\nimport error from \"./error.js\";\nexport { PlugableError } from \"./error.js\";\n\n/**\n * Represents a handler function for a hook.\n *\n * @typeParam T - The type of the arguments passed to the hook handler.\n *\n * @param args - The arguments passed to the hook handler.\n * @param handler - The next hook handler in the chain.\n *\n * @returns A Promise or a value that represents the result of the hook handler.\n * @remarks (TODO)\n * Both args and handler are optional by nature.\n * Differentiate the hook handlers from the user handlers\n */\nexport type Handler<T> = (\n  args: T,\n  handler: Handler<T>,\n) => unknown | void | PromiseLike<unknown> | Handler<T>;\n\n// export type Handler<T> = {\n//   (): unknown | void | PromiseLike<unknown>;\n//   (args: T): unknown | void | PromiseLike<unknown>;\n//   (args: T, handler: Handler<T>): unknown | void | PromiseLike<unknown> | Handler<T>;\n// }\n\n/**\n * Represents a hook in the Plug-and-Play system.\n *\n * @typeParam T - The type of the arguments expected by the hook handlers.\n * @property after - List of plugin names with hooks of the same name that should be executed after this hook. If a string is provided, it is coerced to an array.\n * @property before - List of plugin names with hooks of the same name that should be executed before this hook. If a string is provided, it is coerced to an array.\n * @property handler - The hook handler to be executed.\n * @property name - Name to identify the hook.\n */\nexport interface Hook<T> {\n  after?: string | string[];\n  before?: string | string[];\n  handler: Handler<T>;\n  name?: PropertyKey;\n}\n\n/**\n * Represents a normalized hook with standardized format.\n *\n * @typeParam T - The type of the arguments and return values of the hooks.\n * @typeParam K - The type of the key of the hook in the record.\n * @property after - An array of plugin names that this hook should be executed after.\n * @property before - An array of plugin names that this hook should be executed before.\n * @property handler - The handler function of the hook.\n * @property name - The name of the hook.\n * @property plugin - The name of the plugin that defines this hook.\n * @property require - An array of plugin names that this plugin requires.\n */\nexport interface HookNormalized<T, K extends keyof T> {\n  after: string[];\n  before: string[];\n  handler: Handler<T[K]>;\n  name: K;\n  plugin?: string;\n  require?: string[];\n}\n\n/**\n * Represents a plugin for the Plug-and-Play system.\n *\n * @typeParam T - Type of parameters expected by hook handlers.\n * @property hooks - List of hooks identified by hook names. Each hook can be an array of hooks, a single hook, or a handler function.\n * @property name - Name identifying the plugin by other plugin with the `after`, `before` and `require` properties.\n * @property require - Names of the required plugins. If a required plugin is not registered, an error is thrown when the plugin is registered.\n */\nexport interface Plugin<T> {\n  hooks: {\n    [Name in keyof T]?: Hook<T[Name]>[] | Hook<T[Name]> | Handler<T[Name]>;\n  };\n  name?: PropertyKey;\n  require?: string | string[];\n}\n\n/**\n * Represents a normalized plugin with standardized hooks.\n *\n * @typeParam T - The type of the arguments and return values of the hooks.\n * @property hooks - Hooks associated with the plugin, normalized to a standardized format.\n * @property name - Name identifying the plugin by other plugin with the `after`, `before` and `require` properties.\n * @property require - Names of the required plugins. If a required plugin is not registered, an error is thrown when the plugin is registered.\n */\nexport interface PluginNormalized<T> {\n  hooks: {\n    [Name in keyof T]: HookNormalized<T, Name>[];\n  };\n  name: PropertyKey | undefined;\n  require: string[];\n}\n\n/**\n * Represents the public API of the plugin system.\n *\n * @typeParam T - The type of the arguments and return values of the hooks.\n */\nexport interface Api<T, Chain = undefined> {\n  /**\n   * Execute a handler function and its associated hooks.\n   *\n   * @param options - Options for the synchroneous hook execution.\n   * @param options.args - Argument passed to the handler function as well as all hook handlers.\n   * @param options.handler - Function to decorate, receive the value associated with the `args` property.\n   * @param options.hooks - List of complementary hooks from the end user.\n   * @param options.name - Name of the hook to execute.\n   * @returns - A promise that resolves to the result of the final handler.\n   */\n  call: <K extends keyof T>(options: {\n    args: T[K];\n    handler?: Handler<T[K]>;\n    hooks?: Hook<T[K]>[];\n    name: K;\n  }) => Promise<unknown>;\n  /**\n   * Execute a handler function and its associated hooks synchronously.\n   *\n   * @param options - Options for the asynchroneous hook execution.\n   * @param options.args - Argument passed to the handler function as well as all hook handlers.\n   * @param options.handler - Function to decorate, receive the value associated with the `args` property.\n   * @param options.hooks - List of complementary hooks from the end user.\n   * @param options.name - Name of the hook to execute.\n   * @returns - The result of the final handler.\n   */\n  call_sync: <K extends keyof T>(options: {\n    args: T[K];\n    handler?: Handler<T[K]>;\n    hooks?: Hook<T[K]>[];\n    name: K;\n  }) => unknown;\n  /**\n   * Retrieve the hooks with the given name from all registered plugins, in the order they were registered.\n   *\n   * @param options - Options used to retrieve the hooks. The default is `[]`.\n   * @param options.hooks - List of complementary hooks from the end user. These hooks are merged with the hooks retrieved from the registered plugins.\n   * @param options.name - Names of the hook to retrieve.\n   * @param options.sort - Topological sorting of the hooks relatively to each other using the `after` and `before` properties. If `sort` is `false`, the hooks are returned in the order they were registered. The default is `true`.\n   * @returns - The retrieved hooks.\n   */\n  get: <K extends keyof T>(options: {\n    hooks?: Handler<T[K]> | Hook<T[K]> | Hook<T[K]>[];\n    name: K;\n    sort?: boolean;\n  }) => HookNormalized<T, K>[];\n  /**\n   * Register a new plugin in the system.\n   *\n   * @param plugin - The plugin to register.\n   * @returns - The plugin system.\n   *\n   * @remarks Plugin can be provided when instantiating Plug-And-Play by passing the plugins property or they can be provided later on by calling the register function.\n   *\n   */\n  register: (\n    plugin: Plugin<T> | ((...Args: unknown[]) => Plugin<T>),\n  ) => Chain extends undefined ? this : Chain;\n  /**\n   * Check if a plugin with the given name is registered with the plugin system.\n   *\n   * @param name - The name of the plugin to check.\n   * @returns - True if the plugin is registered, false otherwise.\n   */\n  registered: (name: PropertyKey) => boolean;\n}\n\n/**\n * A function to initialize a plugandplay instance. Creates a plugin system with support for hooks and plugin requirements.\n *\n * @typeParam T - The type of the arguments and return values of the hooks. An object representing the type of every hook arguments.\n * @example\n *\n * Loose typing:\n * ```typescript\n * plugandplay();\n * ```\n *\n * Specific typing:\n * ```typescript\n * plugandplay<{\n *   \"first-hook\" : { bar: number; foo: string };\n *   \"second-hook\" : { baz: object }\n * }>();\n * ```\n * @param options - The options used to initiate the library.\n * @param options.args - The arguments to pass to the registered plugins.\n * @param options.chain - The chain of plugins to call the hooks on.\n * @param options.parent - The parent plugin system to call the hooks on.\n * @param options.plugins - The initial plugins to register.\n * @returns - An object representing the plugin system.\n */\nconst plugandplay = function <\n  T extends Record<string, unknown> = Record<string, unknown>,\n  Chain = undefined,\n>({\n  args = [],\n  chain,\n  parent,\n  plugins = [],\n}: {\n  args?: unknown[];\n  chain?: Chain;\n  parent?: Api<T, Chain>;\n  plugins?: (Plugin<T> | (<FnArgs, T>(...Args: FnArgs[]) => Plugin<T>))[];\n} = {}): Api<T, Chain> {\n  // Internal plugin store\n  const store: PluginNormalized<T>[] = [];\n  // Public API definition\n  const api: Api<T, Chain> = {\n    // Register new plugins\n    register: function (plugin) {\n      if (typeof plugin !== \"function\" && !is_object_literal(plugin)) {\n        throw error(\"PLUGINS_REGISTER_INVALID_ARGUMENT\", [\n          \"a plugin must be an object literal or a function returning an object literal\",\n          \"with keys such as `name`, `required` and `hooks`,\",\n          `got ${JSON.stringify(plugin)} instead.`,\n        ]);\n      }\n      // Obtain plugin from user function\n      plugin = typeof plugin === \"function\" ? plugin(...args) : plugin;\n      // Hook normalization\n      const hooksNormalized = {} as PluginNormalized<T>[\"hooks\"];\n      for (const name in plugin.hooks) {\n        if (!plugin.hooks[name]) continue;\n        hooksNormalized[name] = normalize_hook(name, plugin.hooks[name]);\n      }\n      // Require normalization\n      if (plugin.require && !Array.isArray(plugin.require)) {\n        plugin.require = [plugin.require];\n      }\n      const require =\n        !plugin.require ? []\n        : !Array.isArray(plugin.require) ? [plugin.require]\n        : plugin.require;\n      const requireNormalized: string[] = require.map((require) => {\n        if (typeof require !== \"string\")\n          throw errors.PLUGINS_REGISTER_INVALID_REQUIRE({\n            name: plugin.name,\n            require: require,\n          });\n        return require;\n      });\n      // Plugin normalization\n      const normalizedPlugin: PluginNormalized<T> = {\n        hooks: hooksNormalized,\n        require: requireNormalized,\n        name: plugin.name,\n      };\n      store.push(normalizedPlugin);\n      return (chain ?? this) as any;\n    },\n    registered: function (name) {\n      for (const plugin of store) {\n        if (plugin.name === name) {\n          return true;\n        }\n      }\n      if (parent != null && parent.registered(name)) {\n        return true;\n      }\n      return false;\n    },\n    get: function ({ name, hooks = [], sort = true }) {\n      const normalizedHooks = [\n        // Merge hooks provided by the user\n        ...normalize_hook(name, hooks),\n        // With hooks present in the store\n        ...store\n          .map(function (plugin) {\n            // Only select plugins with the requested hook\n            if (!plugin.hooks[name]) return;\n            // Validate plugin requirements\n            for (const require of plugin.require) {\n              if (!api.registered(require)) {\n                throw errors.REQUIRED_PLUGIN({\n                  plugin: plugin.name,\n                  require: require,\n                });\n              }\n            }\n            return plugin.hooks[name]?.map(\n              (hook) =>\n                ({\n                  plugin: plugin.name,\n                  require: plugin.require,\n                  ...hook,\n                }) as HookNormalized<T, typeof name>,\n            );\n          })\n          .filter(function (hook) {\n            return hook !== undefined;\n          })\n          .flat(1),\n        ...(parent ? parent.get({ name: name, sort: false }) : []),\n      ];\n      if (!sort) {\n        return normalizedHooks;\n      }\n      // Topological sort\n      // Hook index associates plugin names to the requested hook\n      // About PLUGINS_HOOK_[AFTER|BEFORE]_INVALID error:\n      // It is ok for a hook to refer to a non-registered and optional plugin\n      // However, if the plugin exists, then it must expose a hook of the same name.\n      const index: Record<string, HookNormalized<T, typeof name>> = {};\n      for (const hook of normalizedHooks) {\n        if (hook.plugin) index[hook.plugin] = hook;\n      }\n      type Test = [\n        HookNormalized<T, typeof name>,\n        HookNormalized<T, typeof name>,\n      ][];\n      const edges_after = normalizedHooks.map(function (hook) {\n        return hook.after.reduce<Test>(function (result, after) {\n          if (index[after]) {\n            result.push([index[after], hook]);\n          } else if (api.registered(after)) {\n            throw errors.PLUGINS_HOOK_AFTER_INVALID({\n              name: name,\n              plugin: hook.plugin,\n              after: after,\n            });\n          }\n          return result;\n        }, []);\n      });\n      const edges_before = normalizedHooks.map(function (hook) {\n        return hook.before.reduce<Test>(function (result, before) {\n          if (index[before]) {\n            result.push([hook, index[before]]);\n          } else if (api.registered(before)) {\n            throw errors.PLUGINS_HOOK_BEFORE_INVALID({\n              name: name,\n              plugin: hook.plugin,\n              before: before,\n            });\n          }\n          return result;\n        }, []);\n      });\n      const edges = [...edges_after, ...edges_before].flat(1);\n      return toposort.array(normalizedHooks, edges);\n    },\n    // Call a hook against each registered plugin matching the hook name\n    call: async function ({ args, handler, hooks = [], name }) {\n      if (arguments.length !== 1) {\n        throw error(\"PLUGINS_INVALID_ARGUMENTS_NUMBER\", [\n          \"function `call` expect 1 object argument,\",\n          `got ${arguments.length} arguments.`,\n        ]);\n      } else if (!is_object_literal(arguments[0])) {\n        throw error(\"PLUGINS_INVALID_ARGUMENT_PROPERTIES\", [\n          \"function `call` expect argument to be a literal object\",\n          \"with the properties `name`, `args`, `hooks` and `handler`,\",\n          `got ${JSON.stringify(arguments[0])} arguments.`,\n        ]);\n      } else if (typeof name !== \"string\") {\n        throw error(\"PLUGINS_INVALID_ARGUMENT_NAME\", [\n          \"function `call` requires a property `name` in its first argument,\",\n          `got ${JSON.stringify(arguments[0])} argument.`,\n        ]);\n      }\n      // Retrieve the name hooks\n      const hooksNormalized = this.get({\n        hooks: hooks,\n        name: name,\n      });\n      // Call the hooks\n      handler = handler || (() => {});\n      for (const hook of hooksNormalized) {\n        switch (hook.handler.length) {\n          case 0:\n          case 1:\n            await hook.handler(args, () => {});\n            break;\n          case 2:\n            const result = await hook.handler(args, handler);\n            if (result === null) {\n              return null;\n              // Note, this respect the implementation prior the TS migration\n              // See test in call.ts # continue with `undefined` # when `undefined` is returned, sync mode\n              // Not necessarily a good idea, shall be more strict on what the\n              // hook handler might return\n            } else {\n              // }else if(result !== undefined) {\n              // }else if (typeof result === 'function') {\n              handler = result as Handler<T[typeof hook.name]>;\n            }\n            break;\n          default:\n            throw error(\"PLUGINS_INVALID_HOOK_HANDLER\", [\n              \"hook handlers must have 0 to 2 arguments\",\n              `got ${hook.handler.length}`,\n            ]);\n        }\n      }\n      // Call the final handler\n      return handler ? handler(args, () => {}) : undefined;\n    },\n    // Call a hook against each registered plugin matching the hook name\n    call_sync: function ({ args, handler, hooks = [], name }) {\n      if (arguments.length !== 1) {\n        throw error(\"PLUGINS_INVALID_ARGUMENTS_NUMBER\", [\n          \"function `call` expect 1 object argument,\",\n          `got ${arguments.length} arguments.`,\n        ]);\n      } else if (!is_object_literal(arguments[0])) {\n        throw error(\"PLUGINS_INVALID_ARGUMENT_PROPERTIES\", [\n          \"function `call` expect argument to be a literal object\",\n          \"with the properties `name`, `args`, `hooks` and `handler`,\",\n          `got ${JSON.stringify(arguments[0])} arguments.`,\n        ]);\n      } else if (typeof name !== \"string\") {\n        throw error(\"PLUGINS_INVALID_ARGUMENT_NAME\", [\n          \"function `call` requires a property `name` in its first argument,\",\n          `got ${JSON.stringify(arguments[0])} argument.`,\n        ]);\n      }\n      // Retrieve the name hooks\n      const hooksNormalized = this.get({\n        hooks: hooks,\n        name: name,\n      });\n      // Call the hooks\n      handler = handler || (() => {});\n      for (const hook of hooksNormalized) {\n        switch (hook.handler.length) {\n          case 0:\n          case 1:\n            hook.handler(args, () => {});\n            break;\n          case 2:\n            const result = hook.handler(args, handler);\n            if (result === null) {\n              return null;\n              // Note, this respect the implementation prior the TS migration\n              // See test in call.ts # continue with `undefined` # when `undefined` is returned, sync mode\n              // Not necessarily a good idea, shall be more strict on what the\n              // hook handler might return\n            } else {\n              // }else if(result !== undefined) {\n              // }else if (typeof result === 'function') {\n              handler = result as Handler<T[typeof hook.name]>;\n            }\n            break;\n          default:\n            throw error(\"PLUGINS_INVALID_HOOK_HANDLER\", [\n              \"hook handlers must have 0 to 2 arguments\",\n              `got ${hook.handler.length}`,\n            ]);\n        }\n      }\n      // Call the final handler\n      return handler ? handler(args, () => {}) : undefined;\n    },\n  };\n  // Register initial plugins\n  for (const plugin of plugins) {\n    api.register(plugin);\n  }\n  // return the object\n  return api;\n};\n\n/**\n * Normalize a hook definition to a standardized format.\n *\n * @typeParam T - Type of parameters expected by hook handlers.\n *\n * @param name - Name of the hook.\n * @param hook - User-defined hook definition.\n *\n * @returns An array of standardized hook definitions.\n */\nconst normalize_hook = function <T, K extends keyof T>(\n  name: K,\n  hook: Handler<T[K]> | Hook<T[K]> | Hook<T[K]>[],\n): HookNormalized<T, K>[] {\n  const hooks = Array.isArray(hook) ? hook : [hook];\n  return hooks.map(function (hook) {\n    if (typeof hook !== \"function\" && !is_object(hook)) {\n      throw error(\"PLUGINS_HOOK_INVALID_HANDLER\", [\n        \"no hook handler function could be found,\",\n        \"a hook must be defined as a function\",\n        \"or as an object with an handler property,\",\n        `got ${JSON.stringify(hook)} instead.`,\n      ]);\n    }\n    return {\n      after:\n        !(typeof hook !== \"function\" && hook.after) ? []\n        : typeof hook.after === \"string\" ? [hook.after]\n        : hook.after,\n      name: name,\n      before:\n        !(typeof hook !== \"function\" && hook.before) ? []\n        : typeof hook.before === \"string\" ? [hook.before]\n        : hook.before,\n      handler: typeof hook === \"function\" ? hook : hook.handler,\n    };\n  });\n};\n\nconst errors = {\n  PLUGINS_HOOK_AFTER_INVALID: function ({\n    name,\n    plugin,\n    after,\n  }: {\n    name: PropertyKey;\n    plugin: string | undefined;\n    after: string;\n  }) {\n    throw error(\"PLUGINS_HOOK_AFTER_INVALID\", [\n      `the hook ${JSON.stringify(name)}`,\n      plugin ? `in plugin ${JSON.stringify(plugin)}` : \"\",\n      \"references an after dependency\",\n      `in plugin ${JSON.stringify(after)} which does not exists.`,\n    ]);\n  },\n  PLUGINS_HOOK_BEFORE_INVALID: function ({\n    name,\n    plugin,\n    before,\n  }: {\n    name: PropertyKey;\n    plugin: string | undefined;\n    before: string;\n  }) {\n    throw error(\"PLUGINS_HOOK_BEFORE_INVALID\", [\n      `the hook ${JSON.stringify(name)}`,\n      plugin ? `in plugin ${JSON.stringify(plugin)}` : \"\",\n      \"references a before dependency\",\n      `in plugin ${JSON.stringify(before)} which does not exists.`,\n    ]);\n  },\n  REQUIRED_PLUGIN: function ({\n    plugin,\n    require,\n  }: {\n    plugin: PropertyKey | undefined;\n    require: string;\n  }) {\n    throw error(\"REQUIRED_PLUGIN\", [\n      `the plugin ${JSON.stringify(plugin)}`,\n      \"requires a plugin\",\n      `named ${JSON.stringify(require)} which is not unregistered.`,\n    ]);\n  },\n  PLUGINS_REGISTER_INVALID_REQUIRE: function ({\n    name,\n    require,\n  }: {\n    name: PropertyKey | undefined;\n    require: string;\n  }) {\n    throw error(\"PLUGINS_REGISTER_INVALID_REQUIRE\", [\n      \"the `require` property\",\n      name ? `in plugin ${JSON.stringify(name)}` : \"\",\n      \"must be a string or an array,\",\n      `got ${JSON.stringify(require)}.`,\n    ]);\n  },\n};\n\nexport { plugandplay };\n","\nclass PlugableError extends Error {\n  public code: string;\n  [index: string]: unknown;\n  constructor(\n    code: string,\n    message: string | (string | object)[],\n    ...contexts: Record<string, unknown>[]\n  ) {\n    if (Array.isArray(message)) {\n      message = message\n        .filter(function (line) {\n          return !!line;\n        })\n        .join(\" \");\n    }\n    message = `${code}: ${message}`;\n    super(message);\n    if (Error.captureStackTrace) {\n      Error.captureStackTrace(this, PlugableError);\n    }\n    this.code = code;\n    for (let i = 0; i < contexts.length; i++) {\n      const context = contexts[i];\n      for (const key in context) {\n        if (key === \"code\") {\n          continue;\n        }\n        const value = context[key];\n        if (value === void 0) {\n          continue;\n        }\n        this[key] =\n          Buffer.isBuffer(value) ? value.toString()\n          : value === null ? value\n          : JSON.parse(JSON.stringify(value));\n      }\n    }\n  }\n};\nexport { PlugableError };\nexport default (function (...args: ConstructorParameters<typeof PlugableError>) {\n  return new PlugableError(...args);\n});\n"]}