UNPKG

@gpa-gemstone/helper-functions

Version:
167 lines (166 loc) 8.51 kB
"use strict"; // ****************************************************************************************************** // ParseKeyValuePairs.tsx - Gbtc // // Copyright © 2025, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 11/09/2023 - Preston Crawford // Migrated code from GSF. // // ****************************************************************************************************** Object.defineProperty(exports, "__esModule", { value: true }); exports.ParseKeyValuePairs = void 0; var RegexEncode_1 = require("./RegexEncode"); var ReplaceAll_1 = require("./ReplaceAll"); /** * Parses a delimited string into key/value pairs * * @param str - The input string containing key/value pairs. * @param parameterDelimiter - Delimiter between parameters (default `';'`). * @param keyValueDelimiter - Delimiter between key and value (default `'='`). * @param startValueDelimiter - Delimiter marking the start of a nested value (default `'{'`). * @param endValueDelimiter - Delimiter marking the end of a nested value (default `'}'`). * @param ignoreDuplicateKeys - If `true`, later values overwrite earlier ones for duplicate keys (default `true`). * @returns A `Map<string, string>` of parsed keys to their corresponding values. * @throws If any delimiters are not unique, or if nested delimiters are mismatched, or if duplicate keys are disallowed and encountered. */ var ParseKeyValuePairs = function (str, parameterDelimiter, keyValueDelimiter, startValueDelimiter, endValueDelimiter, ignoreDuplicateKeys) { if (parameterDelimiter === void 0) { parameterDelimiter = ';'; } if (keyValueDelimiter === void 0) { keyValueDelimiter = "="; } if (startValueDelimiter === void 0) { startValueDelimiter = "{"; } if (endValueDelimiter === void 0) { endValueDelimiter = "}"; } if (ignoreDuplicateKeys === void 0) { ignoreDuplicateKeys = true; } if (parameterDelimiter === keyValueDelimiter || parameterDelimiter === startValueDelimiter || parameterDelimiter === endValueDelimiter || keyValueDelimiter === startValueDelimiter || keyValueDelimiter === endValueDelimiter || startValueDelimiter === endValueDelimiter) throw "All delimiters must be unique"; var escapedParameterDelimiter = (0, RegexEncode_1.RegexEncode)(parameterDelimiter); var escapedKeyValueDelimiter = (0, RegexEncode_1.RegexEncode)(keyValueDelimiter); var escapedStartValueDelimiter = (0, RegexEncode_1.RegexEncode)(startValueDelimiter); var escapedEndValueDelimiter = (0, RegexEncode_1.RegexEncode)(endValueDelimiter); var backslashDelimiter = (0, RegexEncode_1.RegexEncode)("\\"); var keyValuePairs = new Map(); var escapedValue = []; var valueEscaped = false; var delimiterDepth = 0; // Escape any parameter or key/value delimiters within tagged value sequences // For example, the following string: // "normalKVP=-1; nestedKVP={p1=true; p2=false}") // would be encoded as: // "normalKVP=-1; nestedKVP=p1\\u003dtrue\\u003b p2\\u003dfalse") for (var i = 0; i < str.length; i++) { var character = str[i]; if (character === startValueDelimiter) { if (!valueEscaped) { valueEscaped = true; continue; // Don't add tag start delimiter to final value } // Handle nested delimiters delimiterDepth++; } if (character === endValueDelimiter) { if (valueEscaped) { if (delimiterDepth > 0) { // Handle nested delimiters delimiterDepth--; } else { valueEscaped = false; continue; // Don't add tag stop delimiter to final value } } else { throw "Failed to parse key/value pairs: invalid delimiter mismatch. Encountered end value delimiter \"" + endValueDelimiter + "\" before start value delimiter \"" + startValueDelimiter + "\"."; } } if (valueEscaped) { // Escape any delimiter characters inside nested key/value pair if (character === parameterDelimiter) escapedValue.push(escapedParameterDelimiter); else if (character === keyValueDelimiter) escapedValue.push(escapedKeyValueDelimiter); else if (character === startValueDelimiter) escapedValue.push(escapedStartValueDelimiter); else if (character === endValueDelimiter) escapedValue.push(escapedEndValueDelimiter); else if (character === "\\") escapedValue.push(backslashDelimiter); else escapedValue.push(character); } else { if (character === "\\") escapedValue.push(backslashDelimiter); else escapedValue.push(character); } } if (delimiterDepth !== 0 || valueEscaped) { // If value is still escaped, tagged expression was not terminated if (valueEscaped) delimiterDepth = 1; throw "Failed to parse key/value pairs: invalid delimiter mismatch. Encountered more " + (delimiterDepth > 0 ? "start value delimiters \"" + startValueDelimiter + "\"" : "end value delimiters \"" + endValueDelimiter + "\"") + " than " + (delimiterDepth < 0 ? "start value delimiters \"" + startValueDelimiter + "\"" : "end value delimiters \"" + endValueDelimiter + "\"") + "."; } // Parse key/value pairs from escaped value var pairs = escapedValue.join("").split(parameterDelimiter); for (var i = 0; i < pairs.length; i++) { // Separate key from value var elements = pairs[i].split(keyValueDelimiter); if (elements.length === 2) { // Get key var key = elements[0].trim(); var unescapedValue = elements[1].trim(); // Get unescaped value unescapedValue = (0, ReplaceAll_1.ReplaceAll)(unescapedValue, escapedParameterDelimiter, parameterDelimiter); unescapedValue = (0, ReplaceAll_1.ReplaceAll)(unescapedValue, escapedKeyValueDelimiter, keyValueDelimiter); unescapedValue = (0, ReplaceAll_1.ReplaceAll)(unescapedValue, escapedStartValueDelimiter, startValueDelimiter); unescapedValue = (0, ReplaceAll_1.ReplaceAll)(unescapedValue, escapedEndValueDelimiter, endValueDelimiter); unescapedValue = (0, ReplaceAll_1.ReplaceAll)(unescapedValue, backslashDelimiter, "\\"); // Add key/value pair to dictionary if (ignoreDuplicateKeys) { // Add or replace key elements with unescaped value keyValuePairs.set(key, unescapedValue); } else { // Add key elements with unescaped value throwing an exception for encountered duplicate keys if (keyValuePairs.has(key)) throw "Failed to parse key/value pairs: duplicate key encountered. Key \"" + key + "\" is not unique within the string: \"" + str + "\""; keyValuePairs.set(key, unescapedValue); } } } return keyValuePairs; }; exports.ParseKeyValuePairs = ParseKeyValuePairs;