Dotjs Source Research Notes

Source: Internet
Author: User

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 &&param) {                    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?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.