source: node_modules/es-toolkit/dist/compat/string/template.mjs

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

  • Property mode set to 100644
File size: 3.2 KB
Line 
1import { escape } from './escape.mjs';
2import { attempt } from '../function/attempt.mjs';
3import { defaults } from '../object/defaults.mjs';
4import { toString } from '../util/toString.mjs';
5
6const esTemplateRegExp = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
7const unEscapedRegExp = /['\n\r\u2028\u2029\\]/g;
8const noMatchExp = /($^)/;
9const escapeMap = new Map([
10 ['\\', '\\'],
11 ["'", "'"],
12 ['\n', 'n'],
13 ['\r', 'r'],
14 ['\u2028', 'u2028'],
15 ['\u2029', 'u2029'],
16]);
17function escapeString(match) {
18 return `\\${escapeMap.get(match)}`;
19}
20const defaultInterpolateRegExp = /<%=([\s\S]+?)%>/g;
21const templateSettings = {
22 escape: /<%-([\s\S]+?)%>/g,
23 evaluate: /<%([\s\S]+?)%>/g,
24 interpolate: defaultInterpolateRegExp,
25 variable: '',
26 imports: {
27 _: {
28 escape,
29 template,
30 },
31 },
32};
33function template(string, options, guard) {
34 string = toString(string);
35 if (guard) {
36 options = templateSettings;
37 }
38 options = defaults({ ...options }, templateSettings);
39 const delimitersRegExp = new RegExp([
40 options.escape?.source ?? noMatchExp.source,
41 options.interpolate?.source ?? noMatchExp.source,
42 options.interpolate === defaultInterpolateRegExp ? esTemplateRegExp.source : noMatchExp.source,
43 options.evaluate?.source ?? noMatchExp.source,
44 '$',
45 ].join('|'), 'g');
46 let lastIndex = 0;
47 let isEvaluated = false;
48 let source = `__p += ''`;
49 for (const match of string.matchAll(delimitersRegExp)) {
50 const [fullMatch, escapeValue, interpolateValue, esTemplateValue, evaluateValue] = match;
51 const { index } = match;
52 source += ` + '${string.slice(lastIndex, index).replace(unEscapedRegExp, escapeString)}'`;
53 if (escapeValue) {
54 source += ` + _.escape(${escapeValue})`;
55 }
56 if (interpolateValue) {
57 source += ` + ((${interpolateValue}) == null ? '' : ${interpolateValue})`;
58 }
59 else if (esTemplateValue) {
60 source += ` + ((${esTemplateValue}) == null ? '' : ${esTemplateValue})`;
61 }
62 if (evaluateValue) {
63 source += `;\n${evaluateValue};\n __p += ''`;
64 isEvaluated = true;
65 }
66 lastIndex = index + fullMatch.length;
67 }
68 const imports = defaults({ ...options.imports }, templateSettings.imports);
69 const importsKeys = Object.keys(imports);
70 const importValues = Object.values(imports);
71 const sourceURL = `//# sourceURL=${options.sourceURL ? String(options.sourceURL).replace(/[\r\n]/g, ' ') : `es-toolkit.templateSource[${Date.now()}]`}\n`;
72 const compiledFunction = `function(${options.variable || 'obj'}) {
73 let __p = '';
74 ${options.variable ? '' : 'if (obj == null) { obj = {}; }'}
75 ${isEvaluated ? `function print() { __p += Array.prototype.join.call(arguments, ''); }` : ''}
76 ${options.variable ? source : `with(obj) {\n${source}\n}`}
77 return __p;
78 }`;
79 const result = attempt(() => new Function(...importsKeys, `${sourceURL}return ${compiledFunction}`)(...importValues));
80 result.source = compiledFunction;
81 if (result instanceof Error) {
82 throw result;
83 }
84 return result;
85}
86
87export { template, templateSettings };
Note: See TracBrowser for help on using the repository browser.