utils.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * EJS Embedded JavaScript templates
  3. * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. /**
  19. * Private utility functions
  20. * @module utils
  21. * @private
  22. */
  23. 'use strict';
  24. var regExpChars = /[|\\{}()[\]^$+*?.]/g;
  25. var hasOwnProperty = Object.prototype.hasOwnProperty;
  26. var hasOwn = function (obj, key) { return hasOwnProperty.apply(obj, [key]); };
  27. /**
  28. * Escape characters reserved in regular expressions.
  29. *
  30. * If `string` is `undefined` or `null`, the empty string is returned.
  31. *
  32. * @param {String} string Input string
  33. * @return {String} Escaped string
  34. * @static
  35. * @private
  36. */
  37. exports.escapeRegExpChars = function (string) {
  38. // istanbul ignore if
  39. if (!string) {
  40. return '';
  41. }
  42. return String(string).replace(regExpChars, '\\$&');
  43. };
  44. var _ENCODE_HTML_RULES = {
  45. '&': '&',
  46. '<': '&lt;',
  47. '>': '&gt;',
  48. '"': '&#34;',
  49. "'": '&#39;'
  50. };
  51. var _MATCH_HTML = /[&<>'"]/g;
  52. function encode_char(c) {
  53. return _ENCODE_HTML_RULES[c] || c;
  54. }
  55. /**
  56. * Stringified version of constants used by {@link module:utils.escapeXML}.
  57. *
  58. * It is used in the process of generating {@link ClientFunction}s.
  59. *
  60. * @readonly
  61. * @type {String}
  62. */
  63. var escapeFuncStr =
  64. 'var _ENCODE_HTML_RULES = {\n'
  65. + ' "&": "&amp;"\n'
  66. + ' , "<": "&lt;"\n'
  67. + ' , ">": "&gt;"\n'
  68. + ' , \'"\': "&#34;"\n'
  69. + ' , "\'": "&#39;"\n'
  70. + ' }\n'
  71. + ' , _MATCH_HTML = /[&<>\'"]/g;\n'
  72. + 'function encode_char(c) {\n'
  73. + ' return _ENCODE_HTML_RULES[c] || c;\n'
  74. + '};\n';
  75. /**
  76. * Escape characters reserved in XML.
  77. *
  78. * If `markup` is `undefined` or `null`, the empty string is returned.
  79. *
  80. * @implements {EscapeCallback}
  81. * @param {String} markup Input string
  82. * @return {String} Escaped string
  83. * @static
  84. * @private
  85. */
  86. exports.escapeXML = function (markup) {
  87. return markup == undefined
  88. ? ''
  89. : String(markup)
  90. .replace(_MATCH_HTML, encode_char);
  91. };
  92. function escapeXMLToString() {
  93. return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
  94. }
  95. try {
  96. if (typeof Object.defineProperty === 'function') {
  97. // If the Function prototype is frozen, the "toString" property is non-writable. This means that any objects which inherit this property
  98. // cannot have the property changed using an assignment. If using strict mode, attempting that will cause an error. If not using strict
  99. // mode, attempting that will be silently ignored.
  100. // However, we can still explicitly shadow the prototype's "toString" property by defining a new "toString" property on this object.
  101. Object.defineProperty(exports.escapeXML, 'toString', { value: escapeXMLToString });
  102. } else {
  103. // If Object.defineProperty() doesn't exist, attempt to shadow this property using the assignment operator.
  104. exports.escapeXML.toString = escapeXMLToString;
  105. }
  106. } catch (err) {
  107. console.warn('Unable to set escapeXML.toString (is the Function prototype frozen?)');
  108. }
  109. /**
  110. * Naive copy of properties from one object to another.
  111. * Does not recurse into non-scalar properties
  112. * Does not check to see if the property has a value before copying
  113. *
  114. * @param {Object} to Destination object
  115. * @param {Object} from Source object
  116. * @return {Object} Destination object
  117. * @static
  118. * @private
  119. */
  120. exports.shallowCopy = function (to, from) {
  121. from = from || {};
  122. if ((to !== null) && (to !== undefined)) {
  123. for (var p in from) {
  124. if (!hasOwn(from, p)) {
  125. continue;
  126. }
  127. if (p === '__proto__' || p === 'constructor') {
  128. continue;
  129. }
  130. to[p] = from[p];
  131. }
  132. }
  133. return to;
  134. };
  135. /**
  136. * Naive copy of a list of key names, from one object to another.
  137. * Only copies property if it is actually defined
  138. * Does not recurse into non-scalar properties
  139. *
  140. * @param {Object} to Destination object
  141. * @param {Object} from Source object
  142. * @param {Array} list List of properties to copy
  143. * @return {Object} Destination object
  144. * @static
  145. * @private
  146. */
  147. exports.shallowCopyFromList = function (to, from, list) {
  148. list = list || [];
  149. from = from || {};
  150. if ((to !== null) && (to !== undefined)) {
  151. for (var i = 0; i < list.length; i++) {
  152. var p = list[i];
  153. if (typeof from[p] != 'undefined') {
  154. if (!hasOwn(from, p)) {
  155. continue;
  156. }
  157. if (p === '__proto__' || p === 'constructor') {
  158. continue;
  159. }
  160. to[p] = from[p];
  161. }
  162. }
  163. }
  164. return to;
  165. };
  166. /**
  167. * Simple in-process cache implementation. Does not implement limits of any
  168. * sort.
  169. *
  170. * @implements {Cache}
  171. * @static
  172. * @private
  173. */
  174. exports.cache = {
  175. _data: {},
  176. set: function (key, val) {
  177. this._data[key] = val;
  178. },
  179. get: function (key) {
  180. return this._data[key];
  181. },
  182. remove: function (key) {
  183. delete this._data[key];
  184. },
  185. reset: function () {
  186. this._data = {};
  187. }
  188. };
  189. /**
  190. * Transforms hyphen case variable into camel case.
  191. *
  192. * @param {String} string Hyphen case string
  193. * @return {String} Camel case string
  194. * @static
  195. * @private
  196. */
  197. exports.hyphenToCamel = function (str) {
  198. return str.replace(/-[a-z]/g, function (match) { return match[1].toUpperCase(); });
  199. };
  200. /**
  201. * Returns a null-prototype object in runtimes that support it
  202. *
  203. * @return {Object} Object, prototype will be set to null where possible
  204. * @static
  205. * @private
  206. */
  207. exports.createNullProtoObjWherePossible = (function () {
  208. if (typeof Object.create == 'function') {
  209. return function () {
  210. return Object.create(null);
  211. };
  212. }
  213. if (!({__proto__: null} instanceof Object)) {
  214. return function () {
  215. return {__proto__: null};
  216. };
  217. }
  218. // Not possible, just pass through
  219. return function () {
  220. return {};
  221. };
  222. })();