{"version":3,"file":"parser.cjs","names":[],"sources":["../../../src/experimental/masking/parser.ts"],"sourcesContent":["import { MaskingTransformer } from \"./transformer.js\";\nimport type { MaskingParserConfig } from \"./types.js\";\n\n/**\n * MaskingParser class for handling the masking and rehydrating of messages.\n */\nexport class MaskingParser {\n  private transformers: MaskingTransformer[];\n\n  private state: Map<string, string>;\n\n  private config: MaskingParserConfig;\n\n  constructor(config: MaskingParserConfig = {}) {\n    this.transformers = config.transformers ?? [];\n    this.state = new Map<string, string>();\n    this.config = config;\n  }\n\n  /**\n   * Adds a transformer to the parser.\n   * @param transformer - An instance of a class extending MaskingTransformer.\n   */\n  addTransformer(transformer: MaskingTransformer) {\n    this.transformers.push(transformer);\n  }\n\n  /**\n   * Getter method for retrieving the current state.\n   * @returns The current state map.\n   */\n  public getState(): Map<string, string> {\n    return this.state;\n  }\n\n  /**\n   * Masks the provided message using the added transformers.\n   * This method sequentially applies each transformer's masking logic to the message.\n   * It utilizes a state map to track original values corresponding to their masked versions.\n   *\n   * @param message - The message to be masked.\n   * @returns A masked version of the message.\n   * @throws {TypeError} If the message is not a string.\n   * @throws {Error} If no transformers are added.\n   */\n  async mask(message: string): Promise<string> {\n    // If onMaskingStart is a function, handle it accordingly\n    if (this.config.onMaskingStart) {\n      await this.config.onMaskingStart(message);\n    }\n\n    // Check if there are any transformers added to the parser. If not, throw an error\n    // as masking requires at least one transformer to apply its logic.\n    if (this.transformers.length === 0) {\n      throw new Error(\n        \"MaskingParser.mask Error: No transformers have been added. Please add at least one transformer before parsing.\"\n      );\n    }\n\n    if (typeof message !== \"string\") {\n      throw new TypeError(\n        \"MaskingParser.mask Error: The 'message' argument must be a string.\"\n      );\n    }\n\n    // Initialize the variable to hold the progressively masked message.\n    // It starts as the original message and gets transformed by each transformer.\n    let processedMessage = message;\n\n    // Iterate through each transformer and apply their transform method.\n    for (const transformer of this.transformers) {\n      // Transform the message and get the transformer's state changes, ensuring no direct mutation of the shared state.\n      const [transformedMessage, transformerState] =\n        await transformer.transform(processedMessage, new Map(this.state));\n\n      // Update the processed message for subsequent transformers.\n      processedMessage = transformedMessage;\n\n      // Merge state changes from the transformer into the parser's state.\n      // This accumulates all transformations' effects on the state.\n      transformerState.forEach((value, key) => this.state.set(key, value));\n    }\n\n    // Handle onMaskingEnd callback\n    if (this.config.onMaskingEnd) {\n      await this.config.onMaskingEnd(processedMessage);\n    }\n    // Return the fully masked message after all transformers have been applied.\n    return processedMessage;\n  }\n\n  /**\n   * Rehydrates a masked message back to its original form.\n   * This method sequentially applies the rehydration logic of each added transformer in reverse order.\n   * It relies on the state map to correctly map the masked values back to their original values.\n   *\n   * The rehydration process is essential for restoring the original content of a message\n   * that has been transformed (masked) by the transformers. This process is the inverse of the masking process.\n   *\n   * @param message - The masked message to be rehydrated.\n   * @returns The original (rehydrated) version of the message.\n   */\n  async rehydrate(\n    message: string,\n    state?: Map<string, string>\n  ): Promise<string> {\n    // Handle onRehydratingStart callback\n    if (this.config.onRehydratingStart) {\n      await this.config.onRehydratingStart(message);\n    }\n\n    if (typeof message !== \"string\") {\n      throw new TypeError(\n        \"MaskingParser.rehydrate Error: The 'message' argument must be a string.\"\n      );\n    }\n    // Check if any transformers have been added to the parser.\n    // If no transformers are present, throw an error as rehydration requires at least one transformer.\n    if (this.transformers.length === 0) {\n      throw new Error(\n        \"MaskingParser.rehydrate Error: No transformers have been added. Please add at least one transformer before rehydrating.\"\n      );\n    }\n\n    // oxlint-disable-next-line no-instanceof/no-instanceof\n    if (state && !(state instanceof Map)) {\n      throw new TypeError(\n        \"MaskingParser.rehydrate Error: The 'state' argument, if provided, must be an instance of Map.\"\n      );\n    }\n\n    const rehydrationState = state || this.state; // Use provided state or fallback to internal state\n    // Initialize the rehydratedMessage with the input masked message.\n    // This variable will undergo rehydration by each transformer in reverse order.\n    let rehydratedMessage = message;\n    // Use a reverse for...of loop to accommodate asynchronous rehydrate methods\n    const reversedTransformers = this.transformers.slice().reverse();\n    for (const transformer of reversedTransformers) {\n      // Check if the result is a Promise and use await, otherwise use it directly\n      rehydratedMessage = await transformer.rehydrate(\n        rehydratedMessage,\n        rehydrationState\n      );\n    }\n\n    // Handle onRehydratingEnd callback\n    if (this.config.onRehydratingEnd) {\n      await this.config.onRehydratingEnd(rehydratedMessage);\n    }\n\n    // Return the fully rehydrated message after all transformers have been applied.\n    return rehydratedMessage;\n  }\n}\n"],"mappings":";;;;AAMA,IAAa,gBAAb,MAA2B;CACzB;CAEA;CAEA;CAEA,YAAY,SAA8B,EAAE,EAAE;AAC5C,OAAK,eAAe,OAAO,gBAAgB,EAAE;AAC7C,OAAK,wBAAQ,IAAI,KAAqB;AACtC,OAAK,SAAS;;;;;;CAOhB,eAAe,aAAiC;AAC9C,OAAK,aAAa,KAAK,YAAY;;;;;;CAOrC,WAAuC;AACrC,SAAO,KAAK;;;;;;;;;;;;CAad,MAAM,KAAK,SAAkC;AAE3C,MAAI,KAAK,OAAO,eACd,OAAM,KAAK,OAAO,eAAe,QAAQ;AAK3C,MAAI,KAAK,aAAa,WAAW,EAC/B,OAAM,IAAI,MACR,iHACD;AAGH,MAAI,OAAO,YAAY,SACrB,OAAM,IAAI,UACR,qEACD;EAKH,IAAI,mBAAmB;AAGvB,OAAK,MAAM,eAAe,KAAK,cAAc;GAE3C,MAAM,CAAC,oBAAoB,oBACzB,MAAM,YAAY,UAAU,kBAAkB,IAAI,IAAI,KAAK,MAAM,CAAC;AAGpE,sBAAmB;AAInB,oBAAiB,SAAS,OAAO,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM,CAAC;;AAItE,MAAI,KAAK,OAAO,aACd,OAAM,KAAK,OAAO,aAAa,iBAAiB;AAGlD,SAAO;;;;;;;;;;;;;CAcT,MAAM,UACJ,SACA,OACiB;AAEjB,MAAI,KAAK,OAAO,mBACd,OAAM,KAAK,OAAO,mBAAmB,QAAQ;AAG/C,MAAI,OAAO,YAAY,SACrB,OAAM,IAAI,UACR,0EACD;AAIH,MAAI,KAAK,aAAa,WAAW,EAC/B,OAAM,IAAI,MACR,0HACD;AAIH,MAAI,SAAS,EAAE,iBAAiB,KAC9B,OAAM,IAAI,UACR,gGACD;EAGH,MAAM,mBAAmB,SAAS,KAAK;EAGvC,IAAI,oBAAoB;EAExB,MAAM,uBAAuB,KAAK,aAAa,OAAO,CAAC,SAAS;AAChE,OAAK,MAAM,eAAe,qBAExB,qBAAoB,MAAM,YAAY,UACpC,mBACA,iBACD;AAIH,MAAI,KAAK,OAAO,iBACd,OAAM,KAAK,OAAO,iBAAiB,kBAAkB;AAIvD,SAAO"}