builder/lib/processors/nonAsciiEscaper.js

  1. const escapeUnicode = require("escape-unicode");
  2. /**
  3. * @see https://en.wikipedia.org/wiki/ASCII
  4. * ascii contains 128 characters.
  5. * its char codes reach from 0 to 127.
  6. * @type {number}
  7. */
  8. const CHAR_CODE_OF_LAST_ASCII_CHARACTER = 127;
  9. // use memoization for escapeUnicode function for performance
  10. const memoizeEscapeUnicodeMap = {};
  11. const memoizeEscapeUnicode = function(sChar) {
  12. if (memoizeEscapeUnicodeMap[sChar]) {
  13. return memoizeEscapeUnicodeMap[sChar];
  14. }
  15. memoizeEscapeUnicodeMap[sChar] = escapeUnicode(sChar);
  16. return memoizeEscapeUnicodeMap[sChar];
  17. };
  18. /**
  19. * Escapes non ASCII characters with unicode escape sequences.
  20. *
  21. * @see https://en.wikipedia.org/wiki/ASCII
  22. * @see https://tools.ietf.org/html/rfc5137#section-6.1
  23. *
  24. *
  25. * @param {string} string input string with non ascii characters, e.g. L♥VE
  26. * @returns {{string: (string), modified: boolean}} output string with all non ascii
  27. * characters being escaped by unicode sequence, e.g. L\u2665VE
  28. */
  29. const escapeNonAscii = function(string) {
  30. let result = "";
  31. let modified = false;
  32. for (let i = 0; i < string.length; i++) {
  33. const char = string[i];
  34. // check for non ascii characters (characters which have a char code
  35. // greater than the ascii character code range)
  36. if (string.charCodeAt(i) > CHAR_CODE_OF_LAST_ASCII_CHARACTER) {
  37. result += memoizeEscapeUnicode(char);
  38. modified = true;
  39. } else {
  40. result += char;
  41. }
  42. }
  43. return {
  44. modified,
  45. string: result
  46. };
  47. };
  48. /**
  49. * Escapes non ASCII characters with unicode escape sequences.
  50. *
  51. * @example
  52. * const encoding = nonAsciiEscaper.getEncodingFromAlias("ISO-8859-1");
  53. * nonAsciiEscaper({resources, options: {encoding}});
  54. *
  55. *
  56. * @public
  57. * @alias module:@ui5/builder.processors.nonAsciiEscaper
  58. * @param {object} parameters Parameters
  59. * @param {module:@ui5/fs.Resource[]} parameters.resources List of resources to be processed
  60. * @param {object} [parameters.options] Options
  61. * @param {string} [parameters.options.encoding="utf8"] resource file encoding
  62. * ({@link https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings Node.js character encodings}).
  63. * Use #getEncodingFromAlias to get the encoding string
  64. * @returns {Promise<module:@ui5/fs.Resource[]>} Promise resolving with the processed resources
  65. */
  66. async function nonAsciiEscaper({resources, options: {encoding}}) {
  67. encoding = encoding || "utf8";
  68. async function processResource(resource) {
  69. const resourceString = (await resource.getBuffer()).toString(encoding);
  70. const escaped = escapeNonAscii(resourceString);
  71. // only modify the resource's string if it was changed
  72. if (escaped.modified) {
  73. resource.setString(escaped.string);
  74. }
  75. return resource;
  76. }
  77. return Promise.all(resources.map(processResource));
  78. }
  79. const encodingMap = {
  80. "UTF-8": "utf8",
  81. "ISO-8859-1": "latin1",
  82. };
  83. /**
  84. * Provides a mapping from user-friendly encoding name (alias) such as "UTF-8" and "ISO-8859-1" to node
  85. * specific encoding name such as "utf8" or "latin1". Simplifies usage of nonAsciiEscaper encoding option
  86. * such that it can be used standalone without the respective task (e.g. in Splitter, Bundler and related projects).
  87. *
  88. * @public
  89. * @alias module:@ui5/builder.processors.nonAsciiEscaper․getEncodingFromAlias
  90. * @param {string} encoding encoding labels: "UTF-8" and "ISO-8859-1"
  91. * @returns {string} node.js character encoding string, e.g. utf8 and latin1
  92. */
  93. nonAsciiEscaper.getEncodingFromAlias = function(encoding) {
  94. if (!encodingMap[encoding]) {
  95. throw new Error(
  96. `Encoding "${encoding}" is not supported. Only ${Object.keys(encodingMap).join(", ")} are allowed values` );
  97. }
  98. return encodingMap[encoding];
  99. };
  100. module.exports = nonAsciiEscaper;