First, the entrance method.
/*tmpl: Template text C: User-defined Configuration def: Define data to be executed at compile time */
function (Tmpl, C, def) {}
Then enter the first inning code
c = C | | Dot.templatesettings;
Dot.templatesettings contains the code:
templatesettings: {evaluate:/\{\{([\s\s]+? (\}?) +)\}\}/g, interpolate:/\{\{= ([\s\s]+?) \}\}/g, encode:/\{\{! ([\s\s]+?) \}\}/g, use:/\{\{# ([\s\s]+?) \}\}/g, Useparams:/(^| [^\w$]) Def (?: \.| \[[\ ' \ "]) ([\w$\.] +) (?: [\ ' \ ']\])? \s*\:\s* ([\w$\.] +|\ "[^\"]+\ "|\" [^\ ']+\ ' |\{[^\}]+\})/g, define:/\{\{##\s* ([\w\.$]+) \s* (\:|=) ([\s\s]+?) #\}\}/g, Defineparams:/^\s* ([\w$]+):([\s\s]+]/,//xxx (\w): xxx (.)Conditional:/\{\{\? ( \?)? \s* ([\s\s]*?) \s*\}\}/g, iterate:/\{\{~\s* (?: \} \}| ([\s\s]+?) \s*\:\s* ([\w$]+) \s* (?: \:\ s* ([\w$]+))? \s*\}\})/g, varname:' It ', Strip:true, append:true, selfcontained:false },
Do not hurry to see what is the meaning of the regular, clear ideas first, continue to look at the code
var cse = c.append? Startend.append:startend.split,
This defines a variable called a CSE, if C.append is true, then its value is startend.append, otherwise its value is startend.split, see what StartEnd is
var startend = { "' + (", End: ") + '", endencode: "| |"). ToString (). encodehtml () + ' " }, split: " '; out+= (", End:"); out+= ' ", Endencode:" | | "). ToString (). encodehtml (); out+= ' "} },
OK, regardless of its function, then look down
Needhtmlencode, sid = 0, indv,str = (C.use | | c.define)? resolvedefs (C, Tmpl, Def | | {}): Tmpl;
After defining the CSE variable, NEEDHTMLENCODE,SID,INDV,STR is defined successively, where STR is involved in the function of Resolvedefs:
functionResolvedefs (c, block, Def) {return((typeofblock = = = ' String ')?block:block.toString ()). Replace (C.define|| Skipfunction(m, code, assign, value) {//code:def.def.def.xxx (\w) Assign: ': ' | ' = ' value:xxx (.) if(Code.indexof (' def. ') = = = 0) {Code= Code.substring (4);//get the parts behind Def } if(! (Codeinchdef)) { if(Assign = = = ': ')) { if(c.defineparams) Value.replace (C.defineparams,function(M, Param, v) {//if the next part of DEF is not in the passed in attribute, the value section is detectedDef[code] = {arg:param, text:v};//def.xx:xx:xx }); if(! (Codeinchdef)) def[code]= value;//def.xx:xx}Else { NewFunction ("Def", "def[" "+code+" ']= "+ value) (Def);//Otherwise, value is assigned to Def } } return‘‘; }). replace (C.use|| Skipfunction(m, code) {if(c.useparams) code = code.replace (C.useparams,function(M, S, D, param) {if(Def[d] && def[d].arg &¶m) { varRW = (d+ ":" +param). Replace (/' |\\/g, ' _ ')); Def.__exp= Def.__exp | | {}; DEF.__EXP[RW]= Def[d].text.replace (NewRegExp ("(^|[ ^\\w$]) "+ Def[d].arg +" ([^\\w$]) "," G ")," $ "+ param +" $ "); returnS + "def.__exp[" "+rw+" "; } }); varv =NewFunction ("Def", "return" +code) (Def); returnV?Resolvedefs (c, V, def): v; }); }
This is just more than 100 lines of code dot file is really chewy ah, analysis of the function of the role of
1. First convert block to String type
2. Call string substitution method, regular C.define | | Skip, analyze the c.define.
C.define:/\{\{##\s* ([\w\.$]+) \s* (\:|=) ([\s\s]+?) #\}\}/g
The outermost match content is {{# #一些字符串 #}}, the contents of which are, in order, \s* remove some of the scrambled spaces, the first capture item ([\w\.$]+), matching abc123_.abc123_. This form of content, and then \s* remove some spaces, the second capture item (\:|=) , match ': ' or ' = ', third capture item ([\s\s]+?) Everything matches.
It concludes that the C.define match is {{# # (a random combination of alphanumeric underscores and dots) (: |=) (something that makes up eight bad things) #}, and three parentheses represent a different match.
Looking at the formal parameters of the anonymous function, m corresponds to the entire content being matched, and Code,assign,value represents three different capture items, respectively.
There's a skip:/$^/, right? Only empty words characters this ... It means nothing matches, nothing matches, it's skipped.
3.if statement, if code is to start with def., then the def. back of the content is intercepted and assigned to code
4.if statement, if code is not defined in Def, continue execution
If the assign part is ': ' then continue execution
If C.defineparams has a definition, the value part is replaced with a string, and the regular is C.defineparams
c.defineparams:/^\s* ([\w$]+):([\s\s]+]/
^\s* removes the starting space, ([\w$]+) The first capture item, matches multiple alphanumeric underscores, and then touches: ([\s\s]+) The second capturing item, everything matches
Match Class (Digital letter underline):(a mess of eight bad things), the formal parameter m of the anonymous function represents the entire match, Param represents the first capture item, and V represents the second capturing item
The anonymous function internally defines code with the contents {arg:param, text:v};
If the code above is still not defined in Def, then value is defined in Def and code
Otherwise (if assign is ' = ')
Call, New function ("Def", "def['" "+code+" ']= "+ value) (def); Assign value directly to Def[code], why use a constructor? Because then value can be begged, just like Eval.
To summarize, from 2 to 4, the thing to do is to define the code section of the Def.code, which summarizes the following rules:
(1) def.code:a:b;def[code]={arg:a, text:b}
(2) Def.code:a; Def[code]=a;
(3) Def.code=a; (here A is an expression) def[code]=eval (a);
If the DEF has the code attribute, none of the above three procedures will occur
5. After the above steps, {{# #}} has been parsed, and has been replaced with NULL, the Def object will also have the corresponding property
Continuation of string substitution, regular is C.use | | Skip,skip Needless to say, look directly at C.use.
c.use:/\{\{# ([\s\s]+?) \}\}/g
Shell: {{#}}, ([\s\s]+?), capturing items, and everything, corresponding to anonymous function parameters, M is the entire match, code represents the first capture item,
If statement, if C.useparams exists, the code is replaced with a string, and the regular is C.useparams
c.useparams:/(^|[ ^\w$]) def (?: \.| \[[\ ' \ "]) ([\w$\.] +) (?: [\ ' \ ']\])? \s*\:\s* ([\w$\.] +|\ "[^\"]+\ "|\" [^\ ']+\ ' |\{[^\}]+\})/g,
Long ah ...
(^| [^\w$]) First capture entry, start character or non-alphanumeric underscore ending character,
Def
(?:\.| \[[\ ' \ "]) non-capturing items, matching. or [' or ',
Second capture item ([\w$\.] +), matching abc123_.abc123_.abc123_.,
(?: [\ ' \ ']\])?, matching '] or "], non-greedy match
\s*\:\s*, remove spaces, match:,
([\w$\.] +|\ "[^\"]+\ "|\" [^\ ']+\ ' |\{[^\}]+\}), third capturing item, matching abc123_.abc123_. or "xxxxxx" or ' xxxxxx ', or {xxxxxxx}
The entire regular representation: (some possible special characters) def. (Combination of alphanumeric underscores and dots)[or with [']|['] Wrap up "]":(a combination of alphanumeric underlines and dots | Messy "|" Mess ' | {messy})
M,s,d,param corresponds to the entire match and three capture items respectively
If statement, if DEF[D] and Def[d].arg and Param are present, splice as D:param, and replace the ' and \ ' with _, assign to RW variable
Define DEF.__EXP[RW] to replace special characters +def[d].arg+ special characters in def[d].text with special characters +param+ special characters
return s + "def.__exp['" +rw+ "'"
Summary: In Def.d:param, replace the portion of D.text that conforms to ARG with Param, and d:param (\ and ' Replace with _) as a unique identity RW, assign to Def.__exp, return s + "def.__exp['" +rw+ "']" and replace the Def.d:param, if DEF[D] does not exist, it will be replaced with undefined,
Then run the code (which is actually S + "def.__exp['" "+rw+") that has been parsed in the form of {{#}} and pass the DEF as a parameter, and the result is stored with the variable V
Here, we can know
{{# #}} is equivalent to defining a template, and {{#}} is equivalent to parsing a template
If V is true, the resolvedefs is called recursively until there are no above two labels, and finally, we store the string with the two tags removed in the str variable.
This function can be said to be understood, the role is to extract the template definition in {{# # #}}, and put it into the Def object, and then parse {{#}}, according to the definition in Def, parse it into normal text
Back to the template method
str = ("var out= '" + (C.strip? Str.replace (/(^|\r|\n) \t* +| +\t* (\r|\n|$)/g, ") . Replace (/\r|\n|\t|\/\*[\ s\s]*?\*\//g, "): STR)
Not to be continued
Oh, huh?