formatConversion.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright 2021-2024 Avaiga Private Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  5. * the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  10. * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  11. * specific language governing permissions and limitations under the License.
  12. */
  13. /*
  14. * Regular expressions used for parsing sprintf format strings.
  15. */
  16. const re = {
  17. text: /^[^\x25]+/, // Matches non-placeholder text
  18. modulo: /^\x25{2}/, // Matches the '%%' escape sequence
  19. placeholder: /^\x25?(?:\.(\d+))?([b-giostuvxX])/, // Matches placeholders
  20. };
  21. /*
  22. * This function formats a precision specifier for a number. It takes an optional precision and specifier string.
  23. * If no precision is provided, it defaults to 2. The function returns a string that represents the formatted precision.
  24. */
  25. export const precisionFormat = (precision?: string, specifier?: string): string => {
  26. // Default to precision of 2 if not specified
  27. return "." + (precision?.slice(1) ?? "2") + specifier;
  28. };
  29. /*
  30. * This function parses a sprintf format string and returns an array of strings and objects. Each object has a single
  31. * key, 'placeholder', that contains the placeholder string.
  32. */
  33. export const sprintfParse = (fmt?: string): (string | { placeholder: string })[] => {
  34. let _fmt = fmt;
  35. let match;
  36. const parseTree = [];
  37. while (_fmt) {
  38. if ((match = re.text.exec(_fmt)) !== null) {
  39. // Non-placeholder text
  40. parseTree.push(match[0]);
  41. } else if ((match = re.modulo.exec(_fmt)) !== null) {
  42. // '%%' escape sequence
  43. parseTree.push("%");
  44. } else if ((match = re.placeholder.exec(_fmt)) !== null) {
  45. // Placeholder
  46. if (match && match[0]) {
  47. parseTree.push({
  48. placeholder: match[0],
  49. });
  50. }
  51. } else {
  52. // If none of the conditions are met, break the loop
  53. break;
  54. }
  55. if (match) {
  56. _fmt = _fmt.substring(match[0].length);
  57. }
  58. }
  59. return parseTree;
  60. };
  61. /*
  62. * This function converts a sprintf format string to a D3 format string. It takes an optional sprintf format string and
  63. * returns a D3 format string. If no format string is provided, it returns an empty string.
  64. */
  65. export const sprintfToD3Converter = (fmt?: string): string => {
  66. const sprintfFmtArr = sprintfParse(fmt);
  67. const objectIndex = sprintfFmtArr.findIndex((element) => typeof element === "object");
  68. let placeholderValue;
  69. if (typeof sprintfFmtArr[objectIndex] === "object" && sprintfFmtArr[objectIndex] !== null) {
  70. placeholderValue = (sprintfFmtArr[objectIndex] as { placeholder: string }).placeholder;
  71. }
  72. if (!placeholderValue) {
  73. return "";
  74. }
  75. return placeholderValue.replace(/%([0-9]*)([.][0-9]+)?([bdieufgoxX])/g, (match, width, precision, type) => {
  76. switch (type) {
  77. case "b":
  78. case "d":
  79. case "e":
  80. case "o":
  81. case "x":
  82. case "X":
  83. return type;
  84. case "i":
  85. return "d";
  86. case "f":
  87. case "g":
  88. return precisionFormat(precision, type);
  89. case "u":
  90. return "(";
  91. }
  92. });
  93. };
  94. /*
  95. * This function extracts the prefix from a sprintf format string. It takes an optional sprintf format string and returns
  96. * a string that represents the prefix of the format string. If no format string is provided, it returns an empty string.
  97. */
  98. export const extractPrefix = (fmt?: string): string => {
  99. if (!fmt) return "";
  100. const sprintfFmtArr = sprintfParse(fmt);
  101. const objectIndex = sprintfFmtArr.findIndex((element) => typeof element === "object");
  102. return sprintfFmtArr.slice(0, objectIndex).join("");
  103. };
  104. /*
  105. * This function extracts the suffix from a sprintf format string. It takes an optional sprintf format string and returns
  106. * a string that represents the suffix of the format string. If no format string is provided, it returns an empty string.
  107. */
  108. export const extractSuffix = (fmt?: string): string => {
  109. if (!fmt) return "";
  110. const sprintfFmtArr = sprintfParse(fmt);
  111. const objectIndex = sprintfFmtArr.findIndex((element) => typeof element === "object");
  112. return sprintfFmtArr.slice(objectIndex + 1).join("");
  113. };