You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					102 lines
				
				3.2 KiB
			
		
		
			
		
	
	
					102 lines
				
				3.2 KiB
			| 
											3 years ago
										 | import defaults from './defaults.js'; | ||
|  | import _ from './underscore.js'; | ||
|  | import './templateSettings.js'; | ||
|  | 
 | ||
|  | // When customizing `_.templateSettings`, if you don't want to define an
 | ||
|  | // interpolation, evaluation or escaping regex, we need one that is
 | ||
|  | // guaranteed not to match.
 | ||
|  | var noMatch = /(.)^/; | ||
|  | 
 | ||
|  | // Certain characters need to be escaped so that they can be put into a
 | ||
|  | // string literal.
 | ||
|  | var escapes = { | ||
|  |   "'": "'", | ||
|  |   '\\': '\\', | ||
|  |   '\r': 'r', | ||
|  |   '\n': 'n', | ||
|  |   '\u2028': 'u2028', | ||
|  |   '\u2029': 'u2029' | ||
|  | }; | ||
|  | 
 | ||
|  | var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g; | ||
|  | 
 | ||
|  | function escapeChar(match) { | ||
|  |   return '\\' + escapes[match]; | ||
|  | } | ||
|  | 
 | ||
|  | // In order to prevent third-party code injection through
 | ||
|  | // `_.templateSettings.variable`, we test it against the following regular
 | ||
|  | // expression. It is intentionally a bit more liberal than just matching valid
 | ||
|  | // identifiers, but still prevents possible loopholes through defaults or
 | ||
|  | // destructuring assignment.
 | ||
|  | var bareIdentifier = /^\s*(\w|\$)+\s*$/; | ||
|  | 
 | ||
|  | // JavaScript micro-templating, similar to John Resig's implementation.
 | ||
|  | // Underscore templating handles arbitrary delimiters, preserves whitespace,
 | ||
|  | // and correctly escapes quotes within interpolated code.
 | ||
|  | // NB: `oldSettings` only exists for backwards compatibility.
 | ||
|  | export default function template(text, settings, oldSettings) { | ||
|  |   if (!settings && oldSettings) settings = oldSettings; | ||
|  |   settings = defaults({}, settings, _.templateSettings); | ||
|  | 
 | ||
|  |   // Combine delimiters into one regular expression via alternation.
 | ||
|  |   var matcher = RegExp([ | ||
|  |     (settings.escape || noMatch).source, | ||
|  |     (settings.interpolate || noMatch).source, | ||
|  |     (settings.evaluate || noMatch).source | ||
|  |   ].join('|') + '|$', 'g'); | ||
|  | 
 | ||
|  |   // Compile the template source, escaping string literals appropriately.
 | ||
|  |   var index = 0; | ||
|  |   var source = "__p+='"; | ||
|  |   text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { | ||
|  |     source += text.slice(index, offset).replace(escapeRegExp, escapeChar); | ||
|  |     index = offset + match.length; | ||
|  | 
 | ||
|  |     if (escape) { | ||
|  |       source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; | ||
|  |     } else if (interpolate) { | ||
|  |       source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; | ||
|  |     } else if (evaluate) { | ||
|  |       source += "';\n" + evaluate + "\n__p+='"; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Adobe VMs need the match returned to produce the correct offset.
 | ||
|  |     return match; | ||
|  |   }); | ||
|  |   source += "';\n"; | ||
|  | 
 | ||
|  |   var argument = settings.variable; | ||
|  |   if (argument) { | ||
|  |     // Insure against third-party code injection. (CVE-2021-23358)
 | ||
|  |     if (!bareIdentifier.test(argument)) throw new Error( | ||
|  |       'variable is not a bare identifier: ' + argument | ||
|  |     ); | ||
|  |   } else { | ||
|  |     // If a variable is not specified, place data values in local scope.
 | ||
|  |     source = 'with(obj||{}){\n' + source + '}\n'; | ||
|  |     argument = 'obj'; | ||
|  |   } | ||
|  | 
 | ||
|  |   source = "var __t,__p='',__j=Array.prototype.join," + | ||
|  |     "print=function(){__p+=__j.call(arguments,'');};\n" + | ||
|  |     source + 'return __p;\n'; | ||
|  | 
 | ||
|  |   var render; | ||
|  |   try { | ||
|  |     render = new Function(argument, '_', source); | ||
|  |   } catch (e) { | ||
|  |     e.source = source; | ||
|  |     throw e; | ||
|  |   } | ||
|  | 
 | ||
|  |   var template = function(data) { | ||
|  |     return render.call(this, data, _); | ||
|  |   }; | ||
|  | 
 | ||
|  |   // Provide the compiled source as a convenience for precompilation.
 | ||
|  |   template.source = 'function(' + argument + '){\n' + source + '}'; | ||
|  | 
 | ||
|  |   return template; | ||
|  | } |