langchain
Version:
Typescript bindings for langchain
146 lines (145 loc) • 7.49 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.RegexMaskingTransformer = void 0;
const transformer_js_1 = require("./transformer.cjs");
/**
* RegexMaskingTransformer class for masking and rehydrating messages with Regex.
*/
class RegexMaskingTransformer extends transformer_js_1.MaskingTransformer {
/**
* Constructs a RegexMaskingTransformer with given patterns and an optional hash function.
* Validates the provided patterns to ensure they conform to the expected structure.
*
* @param patterns - An object containing masking patterns. Each pattern should include
* a regular expression (`regex`) and optionally a `replacement` string
* or a `mask` function.
* @param hashFunction - An optional custom hash function to be used for masking.
*/
constructor(patterns, hashFunction) {
super();
Object.defineProperty(this, "patterns", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "hashFunction", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
// Validates the provided masking patterns before initializing the transformer.
// This ensures that each pattern has a valid regular expression.
this.validatePatterns(patterns);
// Assigns the validated patterns and the hash function to the transformer.
// If no custom hash function is provided, the default hash function is used.
this.patterns = patterns;
this.hashFunction = hashFunction || this.defaultHashFunction;
}
/**
* Validates the given masking patterns to ensure each pattern has a valid regular expression.
* Throws an error if any pattern is found to be invalid.
*
* @param patterns - The patterns object to validate.
*/
validatePatterns(patterns) {
for (const key of Object.keys(patterns)) {
const pattern = patterns[key];
// Checks that each pattern is an object and has a regex property that is an instance of RegExp.
// Throws an error if these conditions are not met, indicating an invalid pattern configuration.
if (!pattern ||
typeof pattern !== "object" ||
// eslint-disable-next-line no-instanceof/no-instanceof
!(pattern.regex instanceof RegExp)) {
throw new Error("Invalid pattern configuration.");
}
}
}
/**
* Masks content in a message based on the defined patterns.
* @param message - The message to be masked.
* @param state - The current state containing original values.
* @returns A tuple of the masked message and the updated state.
*/
async transform(message, state) {
if (typeof message !== "string") {
throw new TypeError("RegexMaskingTransformer.transform Error: The 'message' argument must be a string.");
}
// eslint-disable-next-line no-instanceof/no-instanceof
if (!(state instanceof Map)) {
throw new TypeError("RegexMaskingTransformer.transform Error: The 'state' argument must be an instance of Map.");
}
// Holds the progressively masked message
let processedMessage = message;
// Initialize original values map with the current state or a new map
const originalValues = state || new Map();
// Iterate over each pattern defined in the transformer
for (const key of Object.keys(this.patterns)) {
const pattern = this.patterns[key];
// Apply the current pattern's regex to the message
processedMessage = processedMessage.replace(pattern.regex, (match) => {
// Determine the masked value: use the mask function if provided, else use the replacement string,
// else use the hash function.
const maskedValue = pattern.mask
? pattern.mask(match)
: pattern.replacement ?? this.hashFunction(match);
// Store the mapping of the masked value to the original value (match)
originalValues.set(maskedValue, match);
// Return the masked value to replace the original value in the message
return maskedValue;
});
}
// Return the fully masked message and the state map with all original values
// Wrap the synchronous return values in Promise.resolve() to maintain compatibility
// with the MaskingParser's expectation of a Promise return type.
return [processedMessage, originalValues];
}
/**
* Rehydrates a masked message back to its original form using the provided state.
* @param message - The masked message to be rehydrated.
* @param state - The state map containing mappings of masked values to their original values.
* @returns The rehydrated (original) message.
*/
async rehydrate(message, state) {
if (typeof message !== "string") {
throw new TypeError("RegexMaskingTransformer.rehydrate Error: The 'message' argument must be a string.");
}
// eslint-disable-next-line no-instanceof/no-instanceof
if (!(state instanceof Map)) {
throw new TypeError("RegexMaskingTransformer.rehydrate Error: The 'state' argument must be an instance of Map.");
}
// Convert the state map to an array and use reduce to sequentially replace masked values with original values.
const rehydratedMessage = Array.from(state).reduce((msg, [masked, original]) => {
// Escape special characters in the masked string to ensure it can be used in a regular expression safely.
// This is necessary because masked values might contain characters that have special meanings in regex.
const escapedMasked = masked.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// Replace all instances of the escaped masked value in the message with the original value.
// The 'g' flag in the RegExp ensures that all occurrences of the masked value are replaced.
return msg.replace(new RegExp(escapedMasked, "g"), original);
}, message);
return rehydratedMessage;
}
/**
* Default hash function for creating unique hash values.
* @param input - The input string to hash.
* @returns The resulting hash as a string.
*/
defaultHashFunction(input) {
let hash = 0;
// Iterate over each character in the input string
for (let i = 0; i < input.length; i += 1) {
// Get ASCII value of the character
const char = input.charCodeAt(i);
// Combine the current hash with the new character and ensure it remains a 32-bit integer
hash = (hash << 5) - hash + char;
// Bitwise OR operation to convert to a 32-bit integer.
// This is a common technique to ensure the final hash value stays within the 32-bit limit,
// effectively wrapping the value when it becomes too large.
hash |= 0;
}
// Convert the numerical hash value to a string and return
return hash.toString();
}
}
exports.RegexMaskingTransformer = RegexMaskingTransformer;
;