1 2 /** 3 * @name CeL code reorganize function 4 * @fileoverview 5 * 本檔案包含了程式碼重整重構用的 functions。 6 * @since 7 */ 8 9 /* 10 parse code 11 use ISO-14977: Extended Backus–Naur Form (EBNF) 12 http://zh.wikipedia.org/wiki/%E6%89%A9%E5%B1%95%E5%B7%B4%E7%A7%91%E6%96%AF%E8%8C%83%E5%BC%8F 13 14 http://blog.zhaojie.me/2010/11/narcissus-javascript-parser.html 15 Narcissus是一個JavaScript引擎,完全使用JavaScript編寫,不過利用了SpiderMonkey的一些擴展,因此無法直接在僅僅實現了ECMAScript 3的引擎上執行(例如各瀏覽器)。 16 http://en.wikipedia.org/wiki/Narcissus_%28JavaScript_engine%29 17 http://hax.iteye.com/blog/181358 18 19 */ 20 21 if (typeof CeL === 'function'){ 22 23 /** 24 * 本 module 之 name(id),<span style="text-decoration:line-through;">不設定時會從呼叫時之 path 取得</span>。 25 * @type String 26 * @constant 27 * @inner 28 * @ignore 29 */ 30 var module_name = 'code.reorganize'; 31 32 //=================================================== 33 /** 34 * 若欲 include 整個 module 時,需囊括之 code。 35 * @type Function 36 * @param {Function} library_namespace namespace of library 37 * @param load_arguments 呼叫時之 argument(s) 38 * @return 39 * @name CeL.code.reorganize 40 * @constant 41 * @inner 42 * @ignore 43 */ 44 var code_for_including = function (library_namespace, load_arguments) { 45 46 47 var 48 /** 49 * null module constructor 50 * @class 程式碼重整重構相關之 functions。 51 * @constructor 52 */ 53 CeL.code.reorganize 54 = function () { 55 // null module constructor 56 }; 57 58 /** 59 * for JSDT: 有 prototype 才會將之當作 Class 60 */ 61 CeL.code.reorganize 62 .prototype = {}; 63 64 65 66 67 //class public interface --------------------------- 68 69 CeL.code.reorganize 70 . 71 /** 72 * 取得[script_filename].wsf中不包括自己([script_filename].js),其餘所有 .js 的code。 73 * @param {String} script_filename script filename 74 * @return 75 * @requires ScriptName,simpleRead 76 * @deprecated 若想在低版本中利用eval(get_all_functions(ScriptName))來補足,有時會出現奇怪的現象,還是別用好了。 77 * @memberOf CeL.code.reorganize 78 */ 79 get_all_functions = function (script_filename) { 80 if (!script_filename) 81 script_filename = ScriptName; 82 var t = '', i, a = simpleRead(script_filename + '.wsf'), l = a ? a 83 .match(/[^\\\/:*?"<>|'\r\n]+\.js/gi) : [script_filename + '.js']; 84 85 for (i in l) 86 if (l[i] != script_filename + '.js' && (a = simpleRead(l[i]))) 87 t += a; 88 return t; 89 }; 90 91 92 var JS_reserved_word = { 93 Keyword : 'break,do,instanceof,typeof,case,else,new,var,catch,finally,return,void,continue,for,switch,while,debugger,function,this,with,default,if,throw,delete,in,try', 94 FutureReservedWord : 'class,enum,extends,super,const,export,import', 95 NullLiteral : 'null', 96 BooleanLiteral : 'true,false' 97 }; 98 99 100 //var OK = add_code('alert,simpleWrite', ['alert', 'NewLine', 'get_all_functions']);if (typeof OK == 'string') simpleWrite('try.js', OK), alert('done'); else alert('OK:' + OK); 101 /* 102 { 103 var ss = [23, 23.456, undefined, Attribute, null, Array, '567', 'abc'], l = 80, repF = 'tmp.txt', sa = ss, st = add_code('', ['ss']), t; 104 ss = '(reseted)'; try { eval(st); } catch (e) { } t = (sa === ss) + ': ' + typeof sa + '→' + typeof ss + '\n'; 105 simpleWrite(repF, t + sa + '\n→\n' + ss + '\n\n◎eval:\n' + st); 106 alert(t + (sa = '' + sa, sa.length < l ? sa : sa.slice(0, l / 2) + '\n..' + sa.slice(sa.length - l / 2)) + '\n→\n' + (ss = '' + ss, ss.length < l ? ss : ss.slice(0, l / 2) + '\n..' + ss.slice(ss.length - l / 2)) + '\n\n' + (ss = '' + st, ss.length < l ? ss : ss.slice(0, 200) + '\n..\n' + ss.slice(ss.length - 200))); 107 } 108 */ 109 110 /* 111 加入識別格式之方法: 112 113 // from function.js ------------------------------------------------------------------- 114 115 //e.g., 116 // [function.js](f1,f2,'string' // 'string'或"string"中包含的需要是完整的敘述句 117 // number var,string var,object var,date var,undefined var) 118 119 //e.g., 120 // [function.js](OS,NewLine,dirSp,dirSpR,'var ScriptName=getScriptName();',ForReading,ForWriting,ForAppending,TristateUseDefault,TristateTrue,TristateFalse,WshShell,fso,args,'initWScriptObj();',initWScriptObj,setTool,JSalert,Str2Date,Date2Str,decplaces,dQuote,set_obj_value,getScriptFullName,getScriptName,'setTool();',WinEnvironment,SpecialFolder,Network,NetDrive,NetPrinter,getEnvironment,'getEnvironment();',dateUTCdiff,gDate) 121 //e.g., 122 // [function.js]("var NewLine='\n',OS='unix',dirSp=dirSpR='/';",dQuote,setTool,product,decplaces,countS,getText,turnUnicode,trimStr_,trimStr,StrToDate,DateToStr,reducePath,getPathOnly,getFN,getFP,dBasePath,trigger,setTopP,setAstatusOS,setAstatus,setAstatusOver,setAstatusOut,doAlertResize,doAlertInit,doAlert,doAlertAccess,doAlertScroll,setCookie,getCookie,scrollTo,disableKM,setCookieS,*disabledKM=0;,scrollToXY,scrollToInterval,scrollToOK,doAlertDivName,doAlertOldScrollLocation,parse_Function,dealPopup,sPopP,sPopF,sPopInit,sPopInit,sPop,setTextT,setText) 123 124 ..(inclide code) 125 // [function.js]End ------------------------------------------------------------------- 126 // ↑from function.js ------------------------------------------------------------------- 127 128 129 TODO: 130 .htm 加入 .replace(/\//g,'\\/') 131 */ 132 CeL.code.reorganize 133 . 134 /** 135 * 將各 function 加入檔案中,可做成 HTML 亦可用之格式。 136 * @example 137 * add_code('複製 -backup.js'); 138 * @param file_name file name (list) 139 * @param Vlist 多加添的 function/various list 140 * @param {String} start_string start string 141 * @param {String} end_string ending string 142 * @returns 143 * @request NewLine,is_file,simpleRead,autodetectEncode,generate_code,JSalert,setTool,*setTool(); 144 * @memberOf CeL.code.reorganize 145 */ 146 add_code = function (file_name, Vlist, start_string, end_string) { 147 if (!start_string) 148 start_string = '// [' + library_namespace.Class + ']'; 149 if (!end_string) 150 end_string = start_string + 'End'; 151 //alert(is_file(FN)+'\n'+start_string+'\n'+end_string); 152 153 if (typeof file_name == 'string') 154 file_name = [ is_file(file_name) ? file_name : start_string 155 + (file_name ? '(' + file_name + ')' : '') + NewLine 156 + end_string + NewLine ]; 157 if (typeof Vlist == 'string') 158 Vlist = [ Vlist ]; 159 else if (typeof Vlist != 'object') 160 Vlist = []; 161 162 var i, j, F, a, A, start, end, code_head, b, c, d, f, m, OK = 0, new_line, 163 // 「」『』【】〈〉《》〔〕{}︵︶︹︺︷︸︻︼︿﹀︽︾﹁﹂﹃﹄()「」『』‘’“”〝〞‵′ 164 s = '()[]{}<>\u300c\u300d\u300e\u300f\u3010\u3011\u3008\u3009\u300a\u300b\u3014\u3015\uff5b\uff5d\ufe35\ufe36\ufe39\ufe3a\ufe37\ufe38\ufe3b\ufe3c\ufe3f\ufe40\ufe3d\ufe3e\ufe41\ufe42\ufe43\ufe44\uff08\uff09\u300c\u300d\u300e\u300f\u2018\u2019\u201c\u201d\u301d\u301e\u2035\u2032', 165 end_char, req, direct_input = '*', tmpExt = '.tmp', encoding, oriC; 166 167 168 for (i in file_name) try { 169 if (a = oriC = is_file(file_name[i]) ? simpleRead(file_name[i], 170 encoding = autodetectEncode(file_name[i])) : file_name[i], !a) 171 continue; 172 A = '', dones = [], doneS = 0; 173 //sl(a.slice(0,200)); 174 175 /* 判斷 new_line 這段,將三種資料作比較就能知道為何這麼搞。 176 177 ~\r: 178 179 \r 123 180 \n 1 181 \r\n 2 182 \n-\r -120 183 184 185 ~\n: 186 187 \r 1 188 \n 123 189 \r\n 2 190 \n-\r 120 191 192 193 ~\r\n: 194 195 \r 123 196 \n 123 197 \r\n 123 198 \n-\r -2~2 199 */ 200 new_line = a.replace(/[^\n]+/g, '').length; 201 b = a.replace(/[^\r]+/g, '').length; 202 if (new_line != b && new_line && b) { 203 alert("There're some encoding problems in the file:\n" 204 + file_name[i] + '\n\\n: ' + new_line + '\n\\r: ' + b); 205 new_line = Math.max(new_line, b) > 10 * Math.abs(new_line - b) ? '\r\n' 206 : new_line > b ? '\n' : '\r'; 207 } else 208 new_line = new_line ? b ? '\r\n' : '\n' : '\r'; 209 210 //sl(a.indexOf(start_string)+'\n'+start_string+'\n'+a.slice(0,200)); 211 // TODO: a=a.replace(/(startReg)(.*?)(endReg)/g,function($0,$1,$2,$3){.. return $1+~+$3;}); 212 while ((start = a.indexOf(start_string)) != -1 213 // &&(end=a.indexOf(end_string,start+start_string.length))!=-1 214 ) { 215 // initial reset 216 code_head = codeText = end_char = ''; 217 req = []; 218 j = 0; 219 // 判斷 end index 220 if ((end = a.indexOf(end_string, start + start_string.length)) == -1) { 221 alert('add_code: There is start mark without end mark!\nend_string:\n' 222 + end_string); 223 // 未找到格式則 skip 224 break; 225 } 226 // b=inner text 227 b = a.slice(start + start_string.length, end); 228 b = b.split(new_line); //b=b.split(new_line=b.indexOf('\r\n')!=-1?'\r\n':b.indexOf('\n')!=-1?'\n':'\r'); // test檔案型式:DOS or UNIX.最後一位元已被split掉 229 if (c = b[0].match(/^\s*([^\w])/)) { 230 code_head += b[0].slice(0, RegExp.lastIndex); 231 b[0] = b[0].slice(RegExp.lastIndex); 232 if (s.indexOf(c = c[1]) % 2 == 0) 233 end_char = s.charAt(s.indexOf(c) + 1); 234 else 235 end_char = c; 236 } 237 //new_line=b[0].slice(-1)=='\r'?'\r\n':'\n'; // 移到前面:因為需要以new_line作split test檔案型式:DOS or UNIX.最後一位元已被split掉 238 //alert('end_char='+end_char+',j='+j+',d='+d+'\n'+b[0]+'\nNewLine:'+(new_line=='\n'?'\\n':new_line=='\r\n'?'\\r\\n':'\\r')+'\ncode_head:\n'+code_head); 239 240 do { 241 // 不需要d>=b[j].length 242 //if(d==b[j].length)continue; 243 if (!j) 244 d = 0; 245 else if (b[j].slice(0, 2) != '//') 246 continue; 247 else 248 d = 2; 249 250 for (;;) { 251 //alert('search '+b[j].slice(d)); 252 if ((c = b[j].slice(d).match(/^[,\s]*([\'\"])/)) 253 && (f = d + RegExp.lastIndex) <= b[j].length && 254 // (c=c[1], f<b[j].length) 255 (c = c[1]) && f < b[j].length) { // .search( 256 // alert(b[j].charAt(f)+'\n'+c+'\n^(.*[^\\\\])['+c+']'); 257 if (b[j].charAt(f) == c) { 258 // '',""等 259 alert('add_code: 包含[' + c + c + ']:\n' 260 + b[j].slice(f)); 261 continue; 262 } 263 if (c = b[j].slice(f).match( 264 new RegExp('^(.+?[^\\\\])[' + c + ']'))) { 265 d = f + RegExp.lastIndex; 266 req.push(direct_input/* +b[j].charAt(f-1) 改進後不需要了 */ 267 + c[1]); 268 continue; 269 } 270 alert('add_code: Can not find end quota:\n' + b[j].slice(f)); 271 } 272 //alert(d+','+b[j].length+'\nsearch to '+b[j].slice(d)); 273 274 // 出現奇怪現象請加"()" 275 //if((c=b[j].slice(d).match(/([^,\s]+)([,\s]*)/))&& ( (d+=RegExp.lastIndex)==b[j].length || /[,\n]/.test(c[2])&&d<b[j].length ) ){ // 不需要\s\r 276 if ((c = b[j].slice(d).match(/([^,\s]+)[,\s]*/)) && (d += RegExp.lastIndex) <= b[j].length) { // 不需要\s\r 277 //if(!/[,\n]/.test(c[2])&&d<b[j].length)break; 278 //alert(RegExp.index+','+d+','+b[j].length+','+end_char+'\n['+c[1]+']\n['+c[2]+']\n'+b[j].slice(d)); 279 if (!end_char || (m = c[1].indexOf(end_char)) == -1) req.push(c[1]); 280 else { if (m) req.push(c[1].slice(0, m)); end_char = ''; break; } 281 } else break; 282 } 283 code_head += b[j] + new_line; 284 //alert('output start_string:\n'+start_string+'\ncode_head:\n'+code_head); 285 } while (end_char && ++j < b.length); 286 //for(j=0,b=[];j<req.length;j++)b.push(req[j]); // 不能用b=req:object是用參考的,這樣會改到req本身! 287 //for(j=0;j<Vlist.length;j++)b.push(Vlist[j]); // 加入附加的變數 288 289 b = _.generate_code(req.concat(Vlist), new_line, direct_input); 290 codeText = code_head + (arguments.callee.report ? '/* add_code @ ' + gDate('', 1) // report 291 + (req.length ? new_line + ' request variables [' + req.length + ']: ' + req : '') 292 + (Vlist.length ? new_line + ' addition lists [' + Vlist.length + ']: ' + Vlist : '') 293 + (req.length && Vlist.length && b[2].length < req.length + Vlist.length ? new_line + ' Total request [' + b[2].length + ']: ' + b[2] : '') 294 + (b[4].length ? new_line + ' really done [' + b[4].length + ']: ' + b[4] : '') 295 + (b[5].length ? new_line + ' cannot found [' + b[5].length + ']: ' + b[5] : '') 296 + (b[6].length ? new_line + ' all listed [' + b[6].length + ']: ' + b[6] : '') 297 //+(b[3].length?new_line+' included function ['+b[3].length+']: '+b[3]:'') 298 + new_line + ' */' : '') + new_line + _.reduce_code(b[0]).replace(/([};])function(\s)/g, '$1' + new_line + 'function$2').replace(/}var(\s)/g, '}' + new_line + 'var$1')/*.replace(/([;}])([a-z\._\d]+=)/ig,'$1'+new_line+'$2')*/ + new_line + b[1] + new_line; 299 //alert(start+','+end+'\n'+a.length+','+end+','+end_string.length+','+(end+end_string.length)+'\n------------\n'+codeText);//+a.slice(end+end_string.length) 300 A += a.slice(0, start + start_string.length) 301 + codeText 302 + a.substr(end, end_string.length); 303 a = a.substr(end + end_string.length); 304 } 305 306 if (file_name.length == 1 && !is_file(file_name[i])) 307 return A; 308 309 if (A && oriC != A + a) // 有變化才寫入 310 if (!simpleWrite(file_name[i] + tmpExt, A + a, encoding)) 311 try { 312 fso.DeleteFile(file_name[i]); 313 fso.MoveFile(file_name[i] + tmpExt, file_name[i]); 314 OK++; 315 } catch (e) { 316 // popErr(e); 317 } 318 else 319 try { 320 fso.DeleteFile(file_name[i] + tmpExt); 321 } catch (e) { 322 // popErr(simpleFileErr);popErr(e); 323 } 324 //else{alert('add_code error:\n'+e.message);continue;} 325 } catch (e) { 326 //popErr(e); 327 throw e; 328 } 329 330 // A:成功的最後一個檔之內容 331 return file_name.length == 1 && OK == 1 ? A : OK; 332 }; 333 334 /** 335 * 是否加入報告 336 * @type Boolean 337 */ 338 _.add_code.report = false; 339 340 341 CeL.code.reorganize 342 . 343 /** 344 * add libary use 345 * @param {String} code script code 346 * @returns 347 * @memberOf CeL.code.reorganize 348 */ 349 add_use = function (code) { 350 // TODO: 去除 comments 中的 .use() 351 var _s = _.add_use, i, m = code.match(_s.pattern); 352 353 library_namespace.err('TODO'); 354 }; 355 _.add_use.pattern = new RegExp(library_namespace.Class 356 + '\\s*.\\s*use\\((.+)\\)'); 357 358 /* 359 try.wsf 360 <package><job id="try"><script type="text/javascript" language="JScript" src="function.js"></script><script type="text/javascript" language="JScript" src="try.js"></script></job></package> 361 try.js 362 destory_script('WshShell=WScript.CreateObject("WScript.Shell");'+NewLine+NewLine+alert+NewLine+NewLine+'alert("資料讀取錯誤!\\n請檢查設定是否有錯!");'); 363 */ 364 CeL.code.reorganize 365 . 366 /** 367 * script 終結者… 368 * @param {String} code script code 369 * @param addFN 370 * @returns error no. 371 * @memberOf CeL.code.reorganize 372 */ 373 destory_script = function (code, addFN) { 374 try { 375 // input indepent code, additional files 376 var SN = getScriptName(), F, a, listJs, i, len, self = SN + '.js'; 377 if (!code) 378 code = ''; //SN='try'; 379 a = simpleRead(SN + '.wsf'); 380 if (!a) a = ''; 381 // 一網打盡 382 listJs = a.match(/[^\\\/:*?"<>|'\r\n]+\.(js|vbs|hta|s?html?|txt|wsf|pac)/gi); 383 //,listWsf=(SN+'.wsf\n'+a).match(/[^\\\/:*?"<>|'\r\n]+\.wsf/gi); 384 385 for (i = 0, F = {}; i < listJs.length; i++) 386 F[listJs[i]] = 1; 387 if (typeof addFN == 'object') 388 for (i in addFN) 389 F[addFN[i]] = 1; 390 else if (addFN) 391 F[addFN] = 1; 392 393 listJs = []; 394 // 避免重複 395 for (i in F) 396 listJs[listJs.length] = i; 397 //alert(listJs.join('\n')); 398 399 //done all .js @ .wsf & files @ additional list without self 400 for (i = 0; i < listJs.length; i++) 401 // 除了self外殺無赦 402 if (listJs[i] != self) try { 403 if (!listJs[i].match(/\.js$/i) && listJs[i] != SN + '.wsf') { try { fso.DeleteFile(listJs[i], true); } catch (e) { } continue; } // 非.js就讓他死 404 if (changeAttributes(F = fso.GetFile(listJs[i]), '-ReadOnly')) throw 0; // 取消唯讀 405 a = add_null_code(F.size); //a=listJs[i].match(/\.js$/i)?add_null_code(F.size):''; 先確認檔案存在,再幹掉他 406 //alert('done '+listJs[i]+'('+F.size+')\n'+(a.length<500?a:a.slice(0,500)+'..')); 407 simpleWrite(listJs[i], a); 408 } catch (e) { 409 //popErr(e); 410 } 411 412 //done .wsf 413 try { 414 if (changeAttributes(F = fso.GetFile(SN + '.wsf'), '-ReadOnly')) 415 throw 0; 416 a = '<package><job id="' + SN + '"><script type="text/javascript" src="' + SN + '.js"><\/script><\/job><\/package>'; 417 //alert('done '+SN+'.wsf'+'('+F.size+')\n'+a); 418 //a='<package><job id="'+SN+'"><script type="text/javascript" src="function.js"><\/script><script type="text/javascript" src="'+SN+'.js"><\/script><\/job><\/package>'; 419 simpleWrite(SN + '.wsf', a); 420 } catch (e) { 421 //popErr(e); 422 } 423 424 // done self 425 if (listJs.length) try { 426 if (changeAttributes(F = fso.GetFile(self), '-ReadOnly') < 0) 427 throw 0; 428 a = (F.size - code.length) / 2; 429 a = add_null_code(a) + code + add_null_code(a); 430 if (F.Attributes % 2) 431 // 取消唯讀 432 F.Attributes--; 433 //alert('done '+self+'('+F.size+')\n'+(a.length<500?a:a.slice(0,500)+'..')); 434 //a='setTool(),destory_script();'; 435 simpleWrite(self, a); 436 } catch (e) { 437 //popErr(e); 438 } 439 440 //run self & WScript.Quit() 441 //return WshShell.Run('"'+getScriptFullName()+'"'); 442 return 0; 443 } catch (e) { 444 return 1; 445 } 446 }; 447 448 /* for version<5.1:因為不能用.wsf,所以需要合併成一個檔。 449 請將以下函數copy至.js主檔後做適當之變更 450 getScriptName(),merge_script(FN),preCheck(ver) 451 */ 452 // 將script所需之檔案合併 453 // 因為常由preCheck()呼叫,所以所有功能亦需內含。 454 function merge_script(FN) { 455 var i, n, t, SN = getScriptName(), NewLine, fso, ForReading, ForWriting, ForAppending; 456 if (!NewLine) 457 NewLine = '\r\n'; 458 if (!fso) 459 fso = WScript.CreateObject("Scripting.FileSystemObject"); 460 if (!ForReading) 461 ForReading = 1, ForWriting = 2, ForAppending = 8; 462 try { 463 464 // from .wsf 465 /*var F=fso.OpenTextFile(SN+'.wsf',ForReading) 466 //,R=new RegExp('src\s*=\s*["\']?(.+\.js)["\']?\s*','gi') 467 ,a=F.ReadAll();F.Close();*/ 468 a = simpleRead(SN + '.wsf'); 469 S = fso.OpenTextFile(FN, ForWriting, true/* create */); 470 471 try { 472 //t=a.match(/<\s*resource\s+id=(['"].*['"])\s*>((.|\r\n)*?)<\/\s*resource\s*>/gi); 473 // 5.1版以下果然還是不能成功實行,因為改變regexp不能達到目的:沒能找到t。所以在下面第一次test失敗後即放棄;改用.ini設定。 474 var r = new RegExp("<\\s*resource\\s+id=(['\"].*['\"])\\s*>((.|\\r\\n)*?)<\\/\\s*resource\\s*>", "ig"); 475 t = a.match(r); 476 S.WriteLine('// merge_script: from ' + SN + '.wsf'); 477 S.WriteLine("function getResource(id){"); 478 if (!t || !t.length) S.WriteLine(" return ''"); 479 else for (i = 0; i < t.length; i++) { 480 //alert(i+':'+t[i]); 481 //n=t[i].match(/<\s*resource\s+id=(['"].*['"])\s*>((.|\r\n)*?)<\/\s*resource\s*>/i); 482 r = new RegExp("<\\s*resource\\s+id=(['\"].*['\"])\\s*>((.|\\r\\n)*?)<\\/\\s*resource\\s*>", "i"); 483 n = t[i].match(r); 484 S.WriteLine(" " + (i ? ":" : "return ") + "id==" 485 + n[1] + "?'" 486 + n[2].replace(/\r?\n/g, '\\n') + "'"); 487 } 488 S.WriteLine(" :'';" + NewLine + "}" + NewLine); 489 } catch (e) { 490 } 491 492 // from .js 493 t = a.match(/src\s*=\s*["']?(.+\.js)["']?\s*/gi); 494 for (i = 0; i < t.length; i++) { 495 //alert(i+':'+t[i].match(/src\s*=\s*["']?(.+\.js)["']?\s*/i)[1]); 496 //try{F=fso.OpenTextFile(n=t[i].match(/src\s*=\s*["']?(.+\.js)["']?\s*/i)[1],ForReading);} 497 //catch(e){continue;} 498 //S.WriteLine('// merge_script: from script '+n);S.WriteBlankLines(1);S.WriteLine(F.ReadAll()); 499 //S.WriteLine('// merge_script: from script '+n+NewLine+NewLine+F.ReadAll()); 500 //F.Close(); 501 S.WriteLine('// merge_script: from script ' 502 + (n = t[i] 503 .match(/src\s*=\s*["']?(.+\.js)["']?\s*/i)[1]) 504 + NewLine + NewLine + simpleRead(n)); 505 } 506 S.Close(); 507 } catch (e) { 508 return 1; 509 } 510 return 0; 511 }; 512 513 514 515 516 517 //var fa=function(a,s){return '"'+a+k+"'";},fb=function kk(a,t){return a;},fc=new Function('return b+b;'),Locale2=fa,Locale3=fb,Locale4=fc,r=generate_code(['fa','fb','fc','Locale2','Locale3','Locale4','kk']);alert(r.join('\n★'));try{eval(r[0]);alert(fa);}catch(e){alert('error!');} 518 /* use for JSON (JavaScript Object Notation) 519 directly input: [directInput]string 520 輸出string1(可reduce_code),輸出string2(主要為object definition,不需reduce_code,以.replace(/\r\n/g,'')即可reduce),總共要求的變數(去掉重複),包含的函數(可能因參考而有添加),包含的變數(可能因參考而有添加),未包含的變數 521 522 未來:對Array與Object能確實設定之 尚未對應:Object遞迴/special Object(WScript,Excel.Application,內建Object等)/special function(內建函數如Math.floor與其他如WScript.CreateObject等) 523 JScript中對應資料型態,應考慮到內建(intrinsic 或 built-in)物件(Boolean/Date/Function/Number/Array/Object(需注意遞迴:Object之值可為Object))/Time/Error/RegExp/Regular Expression/String/Math)/string/integer/Byte/number(float/\d[de]+-\d/Number.MAX_VALUE/Number.MIN_VALUE)/special number(NaN/正無限值:Number.POSITIVE_INFINITY/負無限值:Number.NEGATIVE_INFINITY/正零/負零)/date/Boolean/undefined(尚未設定值)/undcleared(尚未宣告)/Null/normal Array/normal Object/special Object(WScript,Automation物件如Excel.Application,內建Object等)/function(實體/參考/anonymous)/special function(內建函數如isNaN,Math之屬性&方法Math[.{property|method}]與其他如WScript.CreateObject等)/unknown(others) 524 525 ** 需同步更改 json() 526 527 528 TODO: 529 Object.toSource() 530 Array.toSource() 531 json http://www.json.org/json.js 532 UglifyJS https://github.com/mishoo/UglifyJS 533 534 535 XML Object 536 537 bug: 538 函數定義 .toString() 時無法使用。 539 540 541 使用 \uXXXX 使.js跨語系 542 含中文行 543 → 544 //turnBy 含中文行 545 \x.. 546 考慮註解&執行時語系 547 548 to top BEFORE ANY FUNCTIONS: 549 generate_code.dLK='dependencyList'; // dependency List Key 550 */ 551 CeL.code.reorganize 552 . 553 /** 554 * 利用[*現有的環境*]及變數設定生成code,因此並不能完全重現所有設定,也無法判別函數間的相依關係。 555 * @param {Array} Vlist 變數 list 556 * @param {String} new_line new line 557 * @param {String} direct_input 直接輸入用辨識碼 558 * @requires set_obj_value,dQuote 559 * @memberOf CeL.code.reorganize 560 */ 561 generate_code = function (Vlist, new_line, direct_input) { 562 // vars:處理過的variables(不論是合法或非合法),c:陳述是否已完結 563 var _s = _.generate_code, codeText = '', afterCode = '', vars = [], vari = [], func = [], done = [], undone = [], t, i = 0, c = 0, val, vName, vType; 564 if (!new_line) 565 new_line = '\n'; 566 if (!direct_input) 567 direct_input = _s.ddI; 568 if (typeof Vlist === 'string') 569 Vlist = Vlist.split(_s.dsp); 570 571 for (; i < Vlist.length; i++) if (!((vName = '' + Vlist[i]) in vars)) { 572 // c(continue)=1:var未截止,vName:要加添的變數內容 573 vars[vName] = vari.length, vari.push(vName); // 避免重複 574 575 // 不加入的 576 if (vName.charAt(0) == '-') { 577 vars[vName.slice(1)] = -1; 578 continue; 579 } 580 581 // 直接輸出 582 if (vName.slice(0, direct_input.length) == direct_input) { 583 if (c) 584 codeText += ';' + new_line, c = 0; 585 codeText += val = vName.substr(direct_input.length); 586 done.push('(directly input)' + val); 587 continue; 588 } 589 try { 590 // void 591 eval('vType=typeof(val=' + vName + ');'); 592 } catch (e) { 593 // b:type,c:已起始[var ];catch b:語法錯誤等,m:未定義 594 // e.constructor 595 undone.push((vType ? '(' + vType + ')' : '') + vName 596 + '(error ' + (e.number & 0xFFFF) + ':' 597 + e.description + ')'); 598 continue; 599 } 600 601 602 // or use switch-case 603 if (vType === 'function') { 604 // 加入function object成員,.prototype可用with()。加入函數相依性(dependency) 605 try { 606 eval("var j,k;for(j in " 607 + vName 608 + ")if(j=='" 609 + _s.dLK 610 + "'&&(k=typeof " 611 + vName 612 + "." 613 + _s.dLK 614 + ",k=='string'||" 615 + vName 616 + "." 617 + _s.dLK 618 + " instanceof Array)){j=" 619 + vName 620 + "." 621 + _s.dLK 622 + ";if(k=='string')j=j.split(',');for(k in j)if(j[k])Vlist.push(j[k]);}else Vlist.push('" 623 + vName + ".'+j);for(j in " + vName 624 + ".prototype)Vlist.push('" + vName 625 + ".prototype.'+j);"); 626 } catch (e) { 627 undone.push('(' + vType + ')' + vName + '.[child]' 628 + '(error ' + (e.number & 0xFFFF) + ':' 629 + e.description + ')'); 630 } 631 632 val = ('' + val).replace(/[\r\n]/g, new_line); // function 才會產生 \r\n 問題,所以先處理掉 633 if ((t = val.match(/^\s*function\s*\(/)) || val.match(/^\s*function\s+([\w_]*)([^(]*)\(/)) // 這種判別法不好! 634 if (t || (t = RegExp.$1) == 'anonymous') { 635 func.push(vName); vType = (typeof t == 'string' ? t : 'no named') + ' ' + vType; 636 if (t === 'anonymous') { 637 // 忠於原味(笑) 638 // anonymous 是從new Function(文字列を使って)來的 639 var m = val.match(/\(([^)]*)\)\s*{/), l = RegExp.lastIndex, q = val.match(/[^}]*$/); q = RegExp.index; 640 if (!m) { undone.push('(anonymous function error:' + val + ')' + vName); continue; } 641 if (t = m[1].replace(/,/g, "','")) t = "'" + t + "',"; t = 'new Function(' + t + dQuote(_.reduce_code(val.slice(l, q - 1))) + ')'; 642 } else t = val; 643 } else if (t == vName) { 644 // 関数(function): http://www.interq.or.jp/student/exeal/dss/ejs/1/2.html 645 if (c) codeText += ';' + new_line, c = 0; func.push(vName), codeText += val + new_line; continue; 646 } else if (val.indexOf('[native code]') != -1) { undone.push('(native code function error:' + val + ')' + vName); continue; } // 內建(intrinsic 或 built-in)函數:這種判別法不好! 647 else if (t in vars) done.push('(' + vType + ')' + vName), func.push(vName); // 已經登錄過了,所以就這麼下去.. 648 else { 649 if (c) 650 codeText += ';' + new_line; 651 codeText += val + new_line; 652 vars[t] = vari.length; 653 done.push('(' + vType + ')' + t); 654 func.push(t, vName); 655 c = 0; 656 } 657 else { 658 // unknown error 659 undone.push('(function error:' + val + ')' + vName); 660 continue; 661 } 662 } else if (vType == 'number') { 663 // http://msdn2.microsoft.com/zh-tw/library/y382995a(VS.80).aspx 664 var k = 0, m = 'MAX_VALUE,MIN_VALUE,NEGATIVE_INFINITY,POSITIVE_INFINITY,NaN'.split(','); 665 if (val === NaN || val === Infinity || val === -Infinity) t = '' + val; 666 else for (t = 0; k < m.length; k++) if (val === Number[m[k]]) { t = 'Number.' + m[k]; break; } 667 if (!t) { 668 // http://msdn2.microsoft.com/zh-tw/library/shydc6ax(VS.80).aspx 669 for (k = 0, m = 'E,LN10,LN2,LOG10E,LOG2E,PI,SQRT1_2,SQRT2'.split(','); k < m.length; k++) if (val === Math[m[k]]) { t = 'Math.' + m[k]; break; } 670 if (!t) t = (t = Math.floor(val)) == val && ('' + t).length > (t = '0x' + val.toString(16)).length ? t : val; 671 } 672 } else if (vType == 'boolean' || val === null) t = val; //String(val)//val.toString() // typeof null is 'object' 673 else if (vType == 'string') t = dQuote(val); 674 else if (vType == 'object' && typeof val.getTime == 'function' || vType == 'date') t = 'new Date(' + ((val - new Date) > 999 ? val.getTime() : '') + ')'; // date被當作object 675 // http://msdn2.microsoft.com/en-us/library/dww52sbt.aspx 676 else if (vType == 'object' && /*val.constructor==Error "[object Error]" */('' + val.constructor).indexOf('Error') != -1) 677 t = 'new Error' + (val.number || val.description ? '(' + (val.number || '') + (val.description ? (val.number ? ',' : '') + dQuote(val.description) : '') + ')' : ''); 678 /* 679 else if(vName=='set_obj_value.F'){ // 明白宣示在這裡就插入依存函數:不如用 set_obj_value.F,'set_obj_value();' 680 if(!vars['set_obj_value']||!vars['dQuote'])Vlist=Vlist.slice(0,i).concat('set_obj_value','dQuote',Vlist.slice(i)); 681 Vlist[i--]=directInput+'var set_obj_value.F;';continue; 682 } 683 */ 684 else if (vType == 'object' && (val.constructor == Object || val.constructor == Array)) {// instanceof 685 var k, T = '', T_ = '', T_2 = '', _i = 0, cmC = '\\u002c', eqC = '\\u003d', NL_ = "'" + new_line + "+'", maxLen = 300 - NL_.length; // type;loop用,Text,間距,integer? 686 if (val.constructor == Object) { 687 t = ''; 688 // http://fillano.blog.ithome.com.tw/post/257/59403 689 // ** 一些內建的物件,他的屬性可能會是[[DontEnum]],也就是不可列舉的,而自訂的物件在下一版的ECMA-262中,也可以這樣設定他的屬性。 690 for (k in val) 691 if (typeof val[k] == 'object' || typeof val[k] == 'function') 692 Vlist.push(vName + '.' + k); // 簡單的Object遞迴 693 else { 694 T_2 = k.replace(/,/g, cmC).replace(/=/g, eqC) + '=' + ('' + val[k]).replace(/,/g, cmC).replace(/=/g, eqC) + ','; 695 if (T_.length + T_2.length > maxLen) T += T_ + NL_, T_ = T_2; else T_ += T_2; 696 if (!_i && parseInt(val[k]) == val[k]) _i = 1; else if (_i < 2 && parseFloat(val[k]) == val[k] && parseInt(val[k]) != val[k]) _i = 2; 697 } 698 T += T_; 699 } else {// if(val.constructor==Array) 700 var base = 16, d_, d = -1, k_, kA = []; 701 for (k in val) 702 if (typeof val[k] == 'object' || typeof val[k] == 'function') 703 Vlist.push(vName + '.' + k); // 簡單的Object遞迴 704 else kA.push(parseInt(k) == k ? parseInt(k) : k); // 因為Array中仍有可能存在非數字index 705 kA.sort(), vType = 'Array', t = ',' + base; 706 for (k_ = 0; k_ < kA.length; k_++) { 707 if (!((k = kA[k_]) in val)) { 708 if (d_ != '*') 709 if (k - d == 1) 710 d_ += ','; 711 else 712 d_ = '*'; 713 } else { 714 T_2 = (k - d == 1 ? '' 715 : d_ != '*' && k - d < 3/* k.toString(base).length-1 */? d_ 716 : (isNaN(k) ? k.replace(/,/g, cmC) 717 .replace(/=/g, eqC) 718 : k.toString(base)) 719 + '=') 720 + ('' + val[k]).replace(/,/g, cmC).replace(/=/g, eqC) 721 + ','; 722 d_ = ''; 723 if (T_.length + T_2.length > maxLen) 724 T += T_ + NL_, T_ = T_2; 725 else 726 T_ += T_2; 727 } 728 d = k; 729 if (!_i && parseInt(val[k]) == val[k]) 730 _i = 1; 731 else if (_i < 2 && parseFloat(val[k]) == val[k] 732 && parseInt(val[k]) != val[k]) 733 _i = 2; 734 } 735 T += T_; 736 } 737 if (T) { 738 if (!vars['set_obj_value'] || !vars['dQuote']) { 739 Vlist.push('set_obj_value', 'dQuote'); // 假如沒有set_obj_value則須將之與其所依存之函數(dQuote)一同加入 740 if (!vars['set_obj_value.F']) 741 Vlist.push(direct_input + 'var set_obj_value.F;'); 742 } 743 afterCode += "set_obj_value('" 744 + vName 745 + "','" 746 + T.slice(0, -1) 747 + "'" 748 + (_i ? _i == 1 ? ",1" : ",.1" : t ? ",1" 749 : '') + t + ");" + new_line; 750 t = 1; 751 } else 752 t = vType == 'Object' ? '{}' : '[]'; //new Object(), new Array() 753 } else if (vType == 'object' && val.constructor == RegExp) 754 t = val; 755 else if (vType == 'undefined') 756 // 有定義(var)但沒設定值,可計算undefined數目 757 t = 1; 758 else if (t = 1, vType != 'unknown') 759 if (('' + val).match(/^\s*\[[Oo]bject\s*(\w+)\]\s*$/)) t = RegExp.$1; // 僅對Math有效? 760 else vType = 'unknown type: ' + vType + ' (constructor: ' + val.constructor + ')', alert(vName + ': ' + vType + ', please contract me!\n' + val); // 未知 761 else alert('The type of ' + vName + ' is "' + vType + '"!'); // unknown 762 if (typeof t != 'undefined') { 763 if (vName.indexOf('.') == -1) 764 codeText += (c ? ',' : 'var ') + vName + (t === 1 && vType != 'number' ? '' : '=' + t), c = 1; //alert(codeText.substr(codeText.length-200)); 765 else if (t !== 1 || vType == 'number') 766 codeText += (c ? ';' : '') + vName + '=' + t + ';', 767 c = 0; 768 } 769 done.push('(' + vType + ')' + vName); 770 } 771 if (c) 772 codeText += ';' + new_line; //,c=0;//alert(codeText.substr(codeText.length-200));//alert(afterCode); 773 return [ codeText, afterCode, vari, func, done, undone, Vlist ]; 774 }; 775 /** 776 * default direct input symbol 777 * @type String 778 * @memberOf CeL.code.reorganize 779 */ 780 _.generate_code.ddI = '*'; 781 /** 782 * default separator 783 * @type String 784 * @memberOf CeL.code.reorganize 785 */ 786 _.generate_code.dsp = ','; 787 788 789 790 791 // null code series 792 //simpleWrite('try.js',add_null_code(50000)); 793 var null_code_data, null_code_data_length, add_null_codeD; // 處理null_code的變數暫存,null_code_data[變數名]=變數值,null_code_data_length=length,add_null_codeD:add_null_code data,因為每次都重新執行null_code()很費時間 794 function add_null_code(len, type) { // 為了基底才能加入function而作 795 var s = '', t, l, i, j; if (typeof add_null_codeD != 'object') add_null_codeD = []; qq = 0; 796 while (s.length < len) { 797 /* t=Math.random()<.5?'function':''; 798 s+=len-s.length>9?null_code((len/2>999?999:len/2)+'-'+len,t):null_code(len,t);*/ 799 l = len - s.length > 9 ? len > 2e3 ? 999 : len / 2 : len; 800 j = 0; for (i in add_null_codeD) if (i > l) break; else j = i; 801 if (j && j > 99) { if (len - s.length > 99) t = null_code(null_code(99, 0)), s += (add_null_codeD[t.length] = t); while (len - s.length > j) s += add_null_codeD[j]; } 802 s += j && len - s.length - j < 50 ? add_null_codeD[j] 803 // :(t=null_code(l),add_null_codeD[t.length]=t); 804 : (t = null_code(l) ? add_null_codeD[t.length] = t : ''); 805 } 806 return s; 807 } 808 function null_code_data_add(vari, val) { // variables,value 809 if (vari) { 810 if (typeof null_code_data != 'object') null_code_data = {}, null_code_dataI = [], null_code_data_length = 0; 811 if (!(vari in null_code_data)) null_code_dataI.push(vari), null_code_data_length++; 812 null_code_data[vari] = val; 813 } 814 } 815 //var t=null_code('230-513','function');alert(t.length+'\n'+t); 816 // 817 // 其他方法(有閒情逸致時再加):/**/,//,var vari=num+-*/num,str+-str,if(typeof vari=='~'){},try{eval('~');}catch(e){},eval('try{}catch(e){}');if()WScript.Echo(); 818 CeL.code.reorganize 819 . 820 /** 821 * 產生無用的垃圾碼 822 * @param length \d || \d-\d 823 * @returns {String} 無用的垃圾碼 824 * @see 825 * @memberOf CeL.code.reorganize 826 */ 827 null_code = function (length, type) { 828 // variables;up,down:長度上下限 829 var t = '', vari = [], u, d; 830 if (typeof null_code_data != 'object') 831 null_code_data = {}, null_code_dataI = [], 832 null_code_data_length = 0; 833 if (typeof length == 'number') 834 u = d = Math.floor(length); 835 else if (length = '' + length, (i = length.indexOf('-')) != -1) 836 d = parseInt(length.slice(0, i)), u = parseInt(length 837 .substr(i + 1)); 838 if (u < d) { 839 var a = d; 840 d = u, u = a; 841 } 842 if (!length || !u || length < 0) 843 return ''; 844 if (typeof type != 'string') 845 type = typeof type; 846 847 //if(type=='boolean'){return Math.random()<.5?1:0;} 848 if (type == 'number') { 849 return Math.floor(Math.random() * (u - d) + d); 850 } 851 if (type == 'n2') { 852 if (u < 9 && d < 9) 853 d = Math.pow(10, d), u = Math.pow(10, u); 854 return Math.floor(Math.random() * (u - d) + d); 855 } 856 if (type == 'string') { 857 // if(d<0&&(d=0,u<0)) 858 if (d < 0 && u < (d = 0)) 859 return ''; 860 for ( var i = 0, l = null_code(d + '-' + u, 0), t = []; i < l; i++) 861 t.push(null_code('32-128', 0)); 862 return fromCharCode(t); 863 } 864 if (type == 'vari') { 865 // 變數variables 866 if (d) d--; u--; if (u > 32) u = 32; else if (u < 1) u = 1; // 最長變數:32 867 var a, i, l, c = 0; 868 do { 869 t = [], a = null_code('65-123', 0), i = 0, l = null_code(d + '-' + u, 0); 870 if (a > 90 && a < 97) a = 95; t.push(a); 871 for (; i < l; i++) { a = null_code('55-123', 0); if (a > 90 && a < 97) a = 95; else if (a < 65) a -= 7; t.push(a); } // code:48-57,65-90,95,97-122; 872 t = fromCharCode(t); try { eval('a=typeof ' + t + '!="undefined";'); } catch (e) { } // 確保是新的變數 873 if (c % 9 == 0 && d < u) ++d; 874 } while (++c < 99 && (a || (t in null_code_data))); // 不能確保是新變數的話,給個新的:繼續作。★此作法可能導致長時間的迴圈delay!因此限制最多99次。 875 //if(c==99){alert('重複:['+a+']'+t);WScript.Quit();} 876 return t; 877 } 878 if (type == 'function') { 879 var i = 0, l = null_code('0-9', 0), fN = null_code('2-30', 'vari'), a = NewLine + 'function ' + fN + '(', b = NewLine + '}' + NewLine, v, D = []; // fN:函數名 880 // 只加入函數名 881 null_code_data_add(fN, 'function'); 882 if (l) { 883 for (; i < l; i++) 884 v = null_code('2-30', 'vari'), a += v + ',', D.push(v); 885 a = a.slice(0, -1); 886 } 887 a += '){'; 888 l = (a + b).length + NewLine.length; 889 if (u < l) 890 return null_code(length); 891 return a + (NewLine + null_code((d < l ? 0 : d - l) + '-' 892 + (u - l))).replace(/\n/g, '\n ') + b; 893 } 894 // others:type=='code' 895 var l = null_code(length, 0); 896 while (t.length < l) { 897 var a, v, va = (Math.random() < .5 ? (va = null_code('1-6', 0)) 898 : dQuote(va = null_code('5-' 899 + (u - t.length > 50 ? 50 : u - t.length), 900 'string'))); 901 if (u - t.length > 20 && Math.random() < .9) { 902 if (Math.random() < .7 && null_code_data_length > 9) 903 v = null_code_dataI[null_code(0 + '-' 904 + null_code_data_length, 0)], a = v + '=' + va; 905 else 906 v = null_code('1-9', 'vari'), a = 'var ' + v 907 + (Math.random() < .3 ? '' : '=' + va); 908 a += ';' + (Math.random() < .4 ? NewLine : ''); 909 null_code_data_add(v, va); 910 } else { 911 a = Math.floor(Math.random() * 4); 912 a = a == 1 ? ' ' : a || u < t.length + NewLine.length ? ' ' 913 : NewLine; 914 } 915 if (t.length + a.length <= u) 916 t += a; 917 } 918 return t; 919 }; 920 // ↑null code series 921 922 923 924 /* 925 bug: 926 當每一行都去除\n也可時方能使用!否則會出現「需要;」的錯誤! 927 可能會lose條件式編譯(@cc_on等)的資訊或判別錯誤!另外,尚不保證不會lose或更改程式碼! 928 929 http://www.dreamprojections.com/syntaxhighlighter/Default.aspx 930 931 TODO: 932 將 local various 甚至 global 依頻率縮短,合併以字串組合代替。 selectable 933 safer cut '\r\n' 934 {_exp1_;_exp2_;} → _exp1_,_exp2_; 935 safer cut ';' ;} → } 936 compress: eval("~") 937 938 (function(~){~})(~); 939 940 var fascii2ascii = (function(){ 941 var cclass 942 = '['+String.fromCharCode(0xff01)+'-'+String.fromCharCode(0xff5e)+']'; 943 var re_fullwidth = new RegExp(cclass, 'g'); 944 var substitution = function(m){ 945 return String.fromCharCode(m.charCodeAt(0) - 0xfee0); // 0xff00 - 0x20 946 }; 947 return function(s){ return s.replace(re_fullwidth, substitution) }; 948 })(); 949 950 951 952 953 /*@cc_on OK 954 /*@ cc_on error 955 /* @cc_on 無效 956 957 958 JSlint 可以協助您檢查出有問題的程式碼。 959 http://www.jslint.com/ 960 961 Javascript compressor 962 http://dean.edwards.name/packer/ 963 http://javascriptcompressor.com/ 964 http://www.creativyst.com/Prod/3/ 965 http://www.radok.com/javascript-compression.html 966 http://alex.dojotoolkit.org/shrinksafe/ 967 http://www.saltstorm.net/depo/esc/introduction.wbm 968 */ 969 970 CeL.code.reorganize 971 . 972 /** 973 * 精簡程式碼:去掉註解與\s\n。 974 * use for JSON (JavaScript Object Notation) 975 * @param code 欲精簡之程式碼 976 * @param mode mode=1:''中unicode轉\uHHHH 977 * @returns {String} 精簡後之程式碼 978 * @example 979 * CeL.use('code.reorganize'); 980 * CeL.reduce_code('a + v = ddd;'); 981 * @see 982 * @requires 983 * @memberOf CeL.code.reorganize 984 */ 985 reduce_code = function (code, mode) { 986 if (!code) 987 return ''; //sss=0,mmm=90; 988 var _s = _.reduce_code, reduce_space = _s.reduce_space, A = '', a = '' + code, m, b, q, c, Begin, End; 989 //reduce_codeM=['']; 990 while (a.match(/['"\/]/)) { 991 with (RegExp) 992 Begin = index, End = lastIndex, m = lastMatch; 993 //alert(a); 994 // RegExp.$'等 995 if (Begin && a.charAt(Begin - 1) == '$') { 996 A += reduce_space(a.slice(0, Begin)) + m; 997 a = a.substr(End); 998 continue; 999 } 1000 1001 if (m == '/') if (m = a.charAt(RegExp.lastIndex), m == '*' || m == '/') { // comment 1002 //if(++sss>mmm-2&&alert('sss='+sss+NewLine+a),sss>mmm){alert('comment');break;} 1003 //A+=reduce_space(a.slice(0,Begin)),b=m=='*'?'*/':'\n',m=a.indexOf(b,End+1);//A+=a.slice(0,RegExp.index),b=m=='*'?'*/':'\n',m=a.substr(RegExp.lastIndex).indexOf(b);// 1004 A += reduce_space(a.slice(0, Begin)); 1005 b = m == '*' ? '*/' : '\n'; 1006 m = End + 1; 1007 do { 1008 // 預防「\*/」…其實其他地方(如["'])也需要預防,但沒那精力了。 1009 m = a.indexOf(b, m); 1010 if (a.charAt(m - 1) == '\\') 1011 m += 2; 1012 else 1013 break; 1014 } while (m != -1); 1015 //reduce_codeM.push('find comment: Begin='+Begin+',End='+End+',m='+m+',b='+b.replace(/\n/g,'\\n')+NewLine+(m-End>200||m==-1?a.substr(Begin,200)+'..':a.slice(Begin,m))+NewLine+NewLine+'continue:'+NewLine+a.substr(m+b.length,200)+'..'); 1016 if (m == -1) 1017 if (b == '\n') { a = ''; break; /*return A;*/ } 1018 else throw new Error(1, '[/*] without [*/]!\n' + a.substr(Begin, 200)); 1019 else if ( 1020 // 7: 最起碼應該有這麼多 char 的 comment 才列入查核 1021 7 + End < m && 1022 //a.substring(End+1,m-5).indexOf('@cc_on')==0 不一定只有 cc_on 1023 /^@[cei][a-z_]+/.test(a.substring(End + 1, m - 5)) 1024 ) 1025 //alert('There is conditional compilation detected,\n you may need pay attention to:\n'+a.substring(End+1,m-5)), 1026 // 對條件式編譯全選,預防資訊lose。僅有'/*@cc_on'才列入,\/*\s+@\s+cc_on不可! 1027 A += a.slice(End - 1, m + b.length).replace(/\s*(\/\/[^\r\n]*)?(\r?\n)\s*/g, '$2'), a = a.slice(m + b.length); 1028 else if (a = a.substr(m + b.length), A.match(/\w$/) && a.match(/^\s*\w/)) 1029 // 預防return /*~*/a被轉為returna 1030 A += ' '; 1031 } else { 1032 // RegExp 1033 //reduce_codeM.push('find RegExp: Begin='+Begin+NewLine+a.substr(Begin,200)+NewLine+'-'.x(20)+NewLine+A.substr(A.length-200)+'..'); 1034 b = a.slice(0, Begin), m = 1; //c=Begin,q=End 1035 1036 if (b.match(/(^|[(;+=!{}&|:\\\?,])\s*$/)) 1037 // RegExp:以起頭的'/'前面的字元作判別,前面是這些則為RegExp 1038 m = 1; 1039 else if (b.match(/[\w)\]]\s*$/)) 1040 // 前面是這些則為op 1041 m = 0; 1042 else 1043 // 需再加強前兩項判別之處 1044 throw new Error(1, 1045 'Unknown [/]! Please check it and add rules!\n' 1046 + b + '\n-------------\n' 1047 + a.slice(0, End + 80) 1048 //+'\n-------------\n'+A 1049 ); 1050 1051 if (!m) 1052 //if(!m)A+=a.slice(0,q),a=a.substr(q);// 應該是op之類// 1053 A += reduce_space(a.slice(0, End)), 1054 a = a.substr(End); 1055 else { 1056 A += reduce_space(a.slice(0, Begin)), a = a.substr(Begin), c = 0; //else{A+=a.slice(0,c),a=a.substr(c),c=0;// 1057 //if(++sss>mmm-2&&alert('sss='+sss+'\n'+a),sss>mmm){alert('reg');break;} 1058 while (m = a.substr(c).match(/([^\\]|[\\]{2,})([[\/\n])/)) { // 去掉[] 1059 //reduce_codeM.push('find RegExp [ or / or \\n :'+NewLine+a.substr(c+RegExp.index+1,20)); 1060 if (m[1].length > 1 && m[1].length % 2 == 1) { c += RegExp.lastIndex - 1; continue; } // 奇數個[\]後 1061 else if (m = m[2], m == '/') break; 1062 if (m == '[') 1063 while ((m = a.substr(c += RegExp.lastIndex).match(/([^\\]|[\\]{2,})\]/))) { // 不用c+=RegExp.index+1是因[]中一定得有字元 1064 if (m[1].length > 1 && m[1].length % 2 == 1) { c += RegExp.lastIndex - 1; continue; } // 奇數個[\]後 1065 c += RegExp.lastIndex - 1; m = 1; break; // -1:因為偵測'['時需要前一個字元 1066 //if(++sss>mmm-2&&alert('sss='+sss+'\nc='+c+'\n'+a.substr(c)),sss>mmm){alert('reg 2');break;} 1067 } 1068 if (m != 1) throw new Error(1, 'RegExp error!\nbegin with:\n' + a.substr(Begin, 200)); 1069 } 1070 //reduce_codeM.push('find RegExp 2:'+NewLine+a.slice(0,c+RegExp.lastIndex)); 1071 A += a.slice(0, c += RegExp.lastIndex), a = a.substr(c); //q=RegExp.lastIndex,alert('reg:'+Begin+','+c+','+q+'\n'+a.slice(0,Begin)+'\n-------\n'+a.slice(Begin,c+q)+'\n-------\n'+a.substr(c+q,200));return A; 1072 //q=RegExp.lastIndex,A+=reduce_space(a.slice(0,Begin))+a.slice(Begin,c+=q),a=a.substr(c);//A+=a.slice(0,c+=RegExp.lastIndex),a=a.substr(c);// 1073 } 1074 } else { 1075 // quotation 1076 //alert('quotation:\n'+a) 1077 //reduce_codeM.push('find quotation:'+NewLine+a.substr(RegExp.index,200)); 1078 //if(++sss>mmm-2&&alert('sss='+sss+'\n'+a),sss>mmm){alert('quo');break;} 1079 //c=RegExp.index,b=a.substr(RegExp.lastIndex-1).match(new RegExp('[^\\\\]('+(q=m)+'|\\n)')); 較正式 1080 1081 1082 1083 /* 1084 1085 q=m; // 2009/8/16 15:59:02 FAILED 1086 1087 function test_quotation(){ 1088 '\'; // Error 1089 '\\\'; // Error 1090 '\\\\\'; // Error 1091 ''; 1092 'n'; 1093 '\\'; 1094 'nn'; 1095 '\\n'; 1096 'n\\'; 1097 'n\\n'; 1098 '\\\\'; 1099 '\\\\n'; 1100 'n\\\\'; 1101 'n\\\\n'; 1102 'nn\\\\'; 1103 'nn\\\\n'; 1104 'nnn\\\\'; 1105 'nnn\\\\n'; 1106 } 1107 alert(reduceCode(test_quotation)); 1108 1109 alert(reduceCode(reduceCode)); 1110 */ 1111 1112 /* 1113 // 找到 '\n' 為止,考慮 [\\\\]\\r?\\n 1114 c = Begin + 1, b = ''; 1115 while ((c = a.indexOf('\n', c)) != -1) { 1116 q = a.charAt(c - 1); 1117 if (q == '\\' || q == '\r' && a.charAt(c - 2) == '\\') { 1118 c++; 1119 continue; 1120 } 1121 1122 }; 1123 if (a.charAt(c - 1)) 1124 1125 // alert('use RegExp: '+new 1126 // RegExp('^([^\\\\\\r\\n]*|[\\\\][^\\r\\n]|[\\\\]\\r?\\n)*('+q+'|\\n)')); 1127 b = a.slice(Begin + 1).match( 1128 new RegExp('^([^\\\\\\r\\n]*|[\\\\][^\\r\\n]|[\\\\]\\r?\\n)*(' + q 1129 + '|\\n)')); // too slow! 1130 alert('test string:\n' + a.slice(Begin + 1)) 1131 if (!b || b[2] == '\n') 1132 throw new Error(1, 'There is a start quotation mark [' + q 1133 + '] without a end quotation mark!\nbegin with:\n' 1134 + a.substr(Begin, 200)); // 語法錯誤? 1135 q = RegExp.lastIndex + 1; 1136 */ 1137 1138 // 未考慮 '\n' (不能 check error!) 1139 c = Begin; 1140 q = m; 1141 // 考慮 [\\\\]\\r?\\n 1142 while (b = a.substr(c).match(new RegExp('([^\\\\\\r]|\\\\{2,})(' + q + '|\\r?\\n)'))) 1143 if (b[1].length > 1 && b[1].length % 2 == 1) 1144 c = RegExp.lastIndex - 1; 1145 else 1146 break; 1147 1148 if (!b || b[2] == '\n') 1149 // 語法錯誤? 1150 throw new Error(1, 'There is a start quotation mark [' 1151 + q + '] without a end quotation mark!\nget:[' 1152 + b + ']\nbegin with:\n' + a.substr(Begin, 200)); 1153 //reduce_codeM.push('find quota ['+q+']:'+NewLine+a.substr(c,RegExp.lastIndex)+NewLine+'continue:'+NewLine+a.substr(c+RegExp.lastIndex,99)); 1154 1155 q = RegExp.lastIndex; 1156 1157 1158 1159 //alert('q='+q+',['+b[0]+']'); 1160 //alert(b[1]); 1161 //alert(b[2]); 1162 1163 b = a.substr(Begin, q).replace(/\\\r?\n/g, ''); 1164 //alert('mode='+mode); 1165 if (mode == 1) { 1166 m = ''; 1167 for ( var i = 0; i <= q; i++) 1168 m += b.charCodeAt(i) > 127 ? '\\u' 1169 + b.charCodeAt(i).toString(16) : b 1170 .charAt(i); 1171 } 1172 else m = b; 1173 1174 //A+=a.slice(0,c+=RegExp.lastIndex),a=a.substr(c); 1175 A += reduce_space(a.slice(0, Begin)) + m, a = a.substr(Begin + q); 1176 1177 //alert('A='+A); 1178 //alert('a='+a); 1179 1180 // 對於 ~';{ → ~'{ 或 ~';if → ~'if 不被接受。 1181 //if(!/^[\s\r\n]*\}/.test(a))A+=';'; 1182 } 1183 } 1184 1185 // 後續處理 1186 A += reduce_space(a); 1187 // 這兩行在 reduce_space() 中已處理 1188 //A=A.replace(/([^;])\s*\n+\s*/g,'$1;'); 1189 //A=A.replace(/\s*\n+\s*/g,'');//while(A.match(/\s*\n\s*/))A=A.replace(/\s*\n\s*/g,'');// 1190 1191 return A; 1192 }; 1193 1194 /* tech. data: 1195 1196 string: 1197 ['"]~$1 1198 1199 RegExp: 1200 [/]~$1[a-z]* 1201 [/]~$1[gim]* 1202 =RegExp.[source|test(|exec(] 1203 1204 .match(RegExp) 1205 .replace(RegExp,) 1206 .search(RegExp) 1207 1208 op[/]: 1209 word/word 1210 word/=word 1211 1212 ~: 1213 /\\{0,2,4,6,..}$/ 1214 1215 註解comment: 1216 /*~* / 1217 //~\n 1218 1219 符號denotation:/[+-*=/()&^,<>|!~%\[\]?:{};]+/ 1220 +- 1221 word:/[\w]+/ 1222 1223 program: 1224 ((denotation|word|comment)+(string|RegExp)*)+ 1225 1226 test: 1227 i++ + 1228 a+=++i+4 1229 ++a+i++==++j+ ++e 1230 a++ += ++d 1231 a++ + ++b 1232 1233 for(.*;;) 1234 1235 1236 */ 1237 CeL.code.reorganize 1238 . 1239 /** 1240 * 精簡程式碼部分:去掉\n,;前後的空白等,應由 reduce_code() 呼叫。 1241 * @param code 輸入欲精簡之程式碼 1242 * @returns {String} 精簡後之程式碼 1243 * @see 1244 * http://dean.edwards.name/packer/ 1245 * @memberOf CeL.code.reorganize 1246 */ 1247 reduce_code.reduce_space = function (code) { 1248 // 比下一行快很多,但為了正確性而放棄。 1249 //code=code.replace(/\s*\n+\s/g,''); 1250 // 當每一行都去除\n也可時方能使用!否則會出現「需要;」的錯誤! 1251 code = code 1252 .replace( 1253 /([^\s]?)\s*\n+\s*([^\s]?)/g, 1254 function($0, $1, $2) { 1255 var a = $1, b = $2; 1256 return a 1257 + (a && b && a.match(/\w/) && b.match(/\w/) ? ' ' : '') 1258 + b; 1259 }) 1260 .replace(/\s+$|^\s+/g, ''); 1261 1262 //if(code.match(/\s+$/))code=code.slice(0,RegExp.index); 1263 //if(code.match(/^\s+/))code=code.substr(RegExp.lastIndex); 1264 1265 // 對喜歡將\n當作;的,請使用下面的;但這可能造成失誤,例如[a=(b+c)\nif(~)]與[if(~)\nif(~)] 1266 /* 1267 var m, a; 1268 while (m = code.match(/\s*\n+\s*(.?)/)) 1269 a = RegExp.lastIndex, code = code.slice(0, RegExp.index) 1270 + (m[1].match(/\w/) ? ';' : '') 1271 + code.substr(a - (m[1] ? 1 : 0)); 1272 if (m = code.match(/\s+$/)) 1273 code = code.slice(0, RegExp.index); 1274 if (m = code.match(/^\s+(.?)/)) { 1275 code = code.substr(RegExp.lastIndex - 1); 1276 if ((m[0].indexOf('\n') != -1 && m[1].match(/\w/))) 1277 code = ';' + code; 1278 } 1279 */ 1280 1281 code = code 1282 // 最後再作 1283 //.replace(/([^;])\s*\n+\s*/g,'$1;').replace(/\s*\n+\s*/g,'') 1284 1285 // 因為直接執行下行敘述會將for(~;;也變成for(~;,所以需先作處理。 1286 //.replace(/for\s*\(([^;]*);\s*;/g,'for;#$1#') 1287 // 在''等之中執行此行可能出問題,因此另外置此函數。 1288 //.replace(/\s*;+\s*/g,';') 1289 1290 //.replace(/for;#([^#]*)#/g,'for($1;;') 1291 1292 1293 //.replace(/(.)\s+([+\-]+)/g,function($0,$1,$2){return $1+($1=='+'||$1=='-'?' ':'')+$2;}).replace(/([+-]+)\s+(.)/g,function($0,$1,$2){return $1+($2=='+'||$2=='-'?' ':'')+$2;}) // + ++ + 1294 .replace(/([+\-])\s+([+\-])/g, '$1 $2').replace(/([^+\-])\s+([+-])/g, '$1$2').replace(/([+\-])\s+([^+\-])/g, '$1$2') // + ++ + 1295 1296 .replace(/\s*([()\[\]&|^{*\/%<>,~!?:.]+)\s*/g, '$1') // .replace(/\s*([()\[\]&|{}/%,!]+)\s*/g,'$1') // 去掉'}',因為可能是=function(){};或={'ucC':1}; 1297 .replace(/([a-zA-Z])\s+([=+\-])/g, '$1$2').replace(/([=+\-])\s+([a-zA-Z])/g, '$1$2') 1298 1299 .replace(/\s*([+\-*\/%=!&^<>]+=)\s*/g, '$1') 1300 //.replace(/\s*([{}+\-*/%,!]|[+\-*\/=!<>]?=|++|--)\s*/g,'$1') 1301 1302 1303 // 因為直接執行下行敘述會將for(~;;也變成for(~;,所以需先作處理。 1304 .replace(/for\(([^;]*);;/g, 'for;#$1#') 1305 //.replace(/};+/g,'}') /*.replace(/;{2,}{/g,'{')*/.replace(/{;+/g,'{')//.replace(/;*{;*/g,'{')//在quotation作修正成效不彰 1306 // 去掉'}',因為可能是=function(){};或={'ucC':1}; 1307 .replace(/\s*([{;]);+\s*/g, '$1')//.replace(/\s*([{};]);+\s*/g,'$1') 1308 .replace(/for;#([^#]*)#/g, 'for($1;;') 1309 1310 .replace(/\s{2,}/g, ' ') 1311 .replace(/([^)]);}/g, '$1}') // ~;while(~);} but: ~;i=(~);} , {a.b();} 1312 ; 1313 //if(code.charAt(0)=="'")code=(code.charAt(1)=='}'?'}':code.charAt(1)==';'?'':code.charAt(1))+code.substr(2); 1314 1315 return code; 1316 }; 1317 1318 1319 1320 CeL.code.reorganize 1321 . 1322 /** 1323 * 精簡整個檔的程式碼 1324 * …and test程式是否有語法不全處(例如沒加';') 1325 * @param original_ScriptFileName origin javascript file name 1326 * @param output_ScriptFileName target javascript file name 1327 * @param flag 1328 * flag={doTest:bool,doReport:bool,outEnc:(enc),copyOnFailed:bool,startFrom:// | '',addBefore:'',runBefore:function} 1329 * startFrom 若為 // 則應為 startAfter!! 1330 * @requires autodetectEncode,simpleRead,simpleWrite,reduce_code,is_file 1331 * @deprecated use <a href="http://closure-compiler.appspot.com/" accessdate="2009/12/3 12:13">Closure Compiler Service</a> 1332 * @memberOf CeL.code.reorganize 1333 */ 1334 reduce_script = function (original_ScriptFileName, output_ScriptFileName, flag) { 1335 if (!original_ScriptFileName) 1336 original_ScriptFileName = WScript.ScriptFullName; 1337 1338 if (!output_ScriptFileName) 1339 output_ScriptFileName = 1340 // getFP(original_ScriptFileName.replace(/\.ori/,''),1); 1341 original_ScriptFileName + 1342 //.compressed.js 1343 '.reduced.js'; 1344 1345 if (!flag) 1346 flag = {}; 1347 1348 if (!fso) 1349 fso = new ActiveXObject("Scripting.FileSystemObject"); 1350 1351 // 同檔名偵測(若自行把 .ori 改成標的檔等,把標的檔先 copy 成原來檔案。) 1352 if (original_ScriptFileName == output_ScriptFileName) { 1353 if (2 == WshShell.Popup('origin file and output file is the same!' 1354 + (flag.originFile ? "\nI'll try to copy it back." : ''), 0, 1355 'Copy target as origin file', 1 + 48)) 1356 return; 1357 if (!flag.originFile) 1358 return; 1359 if (is_file(original_ScriptFileName = flag.originFile)) { 1360 alert('origin file is exist! Please rename the file!'); 1361 return; 1362 } 1363 try { 1364 fso.CopyFile(output_ScriptFileName, original_ScriptFileName); 1365 } catch (e) { 1366 alert('Failed to copy file!'); 1367 return; 1368 } 1369 } 1370 1371 if (!is_file(original_ScriptFileName)) { 1372 alert("Doesn't found original javascript file!\n" + original_ScriptFileName); 1373 return; 1374 } 1375 1376 var sp = '='.x(80) + NewLine, reduce_codeM = [], enc = autodetectEncode(original_ScriptFileName), i, outenc = autodetectEncode(output_ScriptFileName); 1377 1378 if (!flag.outEnc) 1379 flag.outEnc = outenc || enc || TristateTrue; 1380 1381 try { 1382 var f = simpleRead(original_ScriptFileName, enc), 1383 ot = simpleRead(output_ScriptFileName, flag.outEnc), r = ''; 1384 if (typeof f != 'string') 1385 throw new Error(1, "Can't read file [" + original_ScriptFileName + "]!"); 1386 t = flag.runBefore ? flag.runBefore(f) || f : f; 1387 if (flag.startFrom) 1388 if (typeof flag.startFrom == 'string') { 1389 if ((i = t.indexOf(flag.startFrom)) != -1) 1390 t = t.slice(i); 1391 } else if (flag.startFrom instanceof RegExp) 1392 t = t.replace(flag.startFrom, ''); 1393 t = reduce_code(t); 1394 t = (flag.addBefore || '') 1395 + t.replace(/([};])function(\s)/g, '$1\nfunction$2').replace( 1396 /}var(\s)/g, '}\nvar$1')/* .replace(/([;}])([a-z\._\d]+=)/ig,'$1\n$2') */ 1397 + reduce_codeM.join(NewLine + sp); 1398 // 不相同才 run 1399 if (t) 1400 if (t != ot || outenc != flag.outEnc) 1401 simpleWrite(output_ScriptFileName, t, flag.outEnc); 1402 else 1403 r = '* 欲寫入之內容(' + t.length + ' chars)與標的檔相同。檔案並未變更。\n'; 1404 1405 if (flag.doTest) 1406 // void //should use windows.eval 1407 // //if(WScript.ScriptName!=output_ScriptFileName)eval(t); 1408 eval('if(0){if(0){if(0){' + t + '}}}'); 1409 if (flag.doReport) 1410 alert('OK!\n' + r + '\n' + f.length + '→' + t.length 1411 + '(origin output: ' + ot.length + ') (' 1412 + (100 * t.length / f.length).decp(2) + '%)\n\n[' + enc 1413 + '] ' + original_ScriptFileName + '\n→\n[' + flag.outEnc 1414 + '] ' + output_ScriptFileName); 1415 } catch (e) { 1416 if (6 == alert( 1417 'reduce_script: Error occured!\nDo you want to write error message to target file?\n' 1418 + output_ScriptFileName, 0, 0, 3 + 32)) 1419 simpleWrite(output_ScriptFileName, popErr(e) + NewLine + NewLine 1420 + reduce_codeM.join(NewLine + sp), TristateTrue/* enc */, 0, 1421 true); 1422 if (flag.copyOnFailed) 1423 try { 1424 fso.CopyFile(original_ScriptFileName, output_ScriptFileName); 1425 } catch (e) { 1426 alert('Failed to copy file!'); 1427 return; 1428 } 1429 } 1430 }; 1431 1432 1433 1434 1435 /* 1436 !! arguments unfinished !! 1437 1438 usage: include code in front: 1439 // [function.js]_iF,rJS 1440 // [function.js]End 1441 1442 rJS({add:'/*\nCopyright 2008 kanashimi\n欲使用此工具功能者,請聯絡作者。\n*\/\n'}); 1443 1444 // code start 1445 1446 (main code).. 1447 1448 */ 1449 CeL.code.reorganize 1450 . 1451 /** 1452 * 縮減 HTML 用 .js大小+自動判別。 1453 * TODO: 1454 * 自動選擇 target 之模式(不一定是 .ori) 1455 * @param flag flag 1456 * @requires reduce_script 1457 * @since 2008/7/31 17:40:40 1458 * @memberOf CeL.code.reorganize 1459 */ 1460 rJS = function (flag) { 1461 if (typeof WScript == 'object') { 1462 var o = WScript, t, n; 1463 1464 if (typeof reduce_script != 'function') 1465 o.Echo('Please include function reduce_script() to generate code.'); 1466 else 1467 flag = flag || {}, 1468 n = o.ScriptFullName, 1469 t = n.replace(/\.ori/, ''), 1470 reduce_script(n, t, { 1471 doReport : 1, 1472 outEnc : 'UTF-8', 1473 startFrom : flag.cut || /^(.|\n)+code\s+start\r?\n/, 1474 addBefore : flag.add, 1475 originFile : t.replace(flag.ori || /(\.[^.]+)$/, '.ori$1') 1476 }); 1477 1478 o.Quit(); 1479 } 1480 }; 1481 1482 1483 /* 1484 try{var o;try{o=new ActiveXObject('Microsoft.XMLHTTP')}catch(e){o=new XMLHttpRequest()}with(o)open('GET',(new ActiveXObject("WScript.Shell")).RegRead('HKCU\\Software\\Colorless echo\\CeL.path'),false),send(null),eval(responseText)}catch(e){} 1485 1486 */ 1487 //(''+CeL.library_loader).replace(/^\s*function\s*\(\s*\)\s*{\s*/,'').replace(/\s*}\s*;\s*$/,''); 1488 CeL.code.reorganize 1489 . 1490 /** 1491 * for 引用: include library 自 registry 中的 path 1492 * @since 2009/11/25 22:59:02 1493 * @_memberOf _module_ 1494 */ 1495 library_loader_by_registry = function () { 1496 //if (typeof WScript == "object") 1497 try { 1498 var o; 1499 try { 1500 o = new ActiveXObject('Microsoft.XMLHTTP'); 1501 } catch (e) { 1502 o = new XMLHttpRequest(); 1503 } 1504 with (o) 1505 open('GET', (new ActiveXObject("WScript.Shell")).RegRead(library_namespace.env.registry_key), false), 1506 send(null), 1507 eval(responseText); 1508 } catch (e) { 1509 } 1510 }; 1511 1512 1513 CeL.code.reorganize 1514 . 1515 /** 1516 * get various from code 1517 * @param {String} code 程式碼 1518 * @param {Boolean} fill_code (TODO) 不只是定義,在 .code 填入程式碼。 1519 * @return {Object} root namespace 1520 * @since 2009/12/5 15:04:42, 2009/12/20 14:33:30, 2010/7/7 10:58:22 1521 * @_memberOf _module_ 1522 */ 1523 get_various_from_code = function (code, fill_code) { 1524 //library_namespace.log(''+code.slice(0, 100)); 1525 1526 // 使用 .split(/\r?\n/) 應注意:這實際上等於 .split(/(\r?\n)+/) (??) 1527 code = code.split(/\r?\n/); 1528 1529 var i, m, last_code = [], 1530 /** 1531 * 現在所處之 line 1532 * 1533 * @inner 1534 * @ignore 1535 */ 1536 line = '', 1537 /** 1538 * code.length, 加快速度用 1539 * 1540 * @constant 1541 * @inner 1542 * @ignore 1543 */ 1544 l = code.length, 1545 /** 1546 * root namespace 1547 * 1548 * @inner 1549 * @ignore 1550 */ 1551 ns = {}, 1552 /** 1553 * 暫存 code(變數定義) 1554 * 1555 * @inner 1556 * @ignore 1557 */ 1558 tmp_code, 1559 /** 1560 * 名稱暫存變數 1561 * 1562 * @inner 1563 * @ignore 1564 */ 1565 name, 1566 /** 1567 * arguments 暫存變數<br/> 1568 * e.g., 變數 name 1569 * 1570 * @inner 1571 * @ignore 1572 */ 1573 various, 1574 /** 1575 * 本變數之 properties。<br/> 1576 * properties = { property: text contents of this property } 1577 * 1578 * @inner 1579 * @ignore 1580 */ 1581 properties, 1582 /** 1583 * 最後一次定義的變數名,用於之後若有變數需要繼承 namespace 時。 1584 * 1585 * @inner 1586 * @ignore 1587 */ 1588 latest_name, 1589 /** 1590 * 紀錄有意義的註解所在行號. 1591 * 預防需要把註解之前的也讀進來。有 bug! 1592 * 1593 * @inner 1594 * @ignore 1595 */ 1596 origin_index, 1597 new_line=library_namespace.env.new_line, 1598 /** 1599 * 將 jsdoc properties 轉換成 VSdoc(JScript IntelliSense in Visual Studio) 1600 * 1601 * @inner 1602 * @ignore 1603 * @see 1604 * http://weblogs.asp.net/bleroy/archive/2007/04/23/the-format-for-javascript-doc-comments.aspx, 1605 * http://msdn.microsoft.com/zh-tw/library/bb385682.aspx, 1606 * http://www.codeproject.com/Articles/60661/Visual-Studio-JavaScript-Intellisense-Revisited.aspx 1607 */ 1608 jsdoc_to_vsdoc = function() { 1609 var p = [ '' ], n, V, a, i, l, t_p = function(v) { 1610 //CeL.log(n + ':\n' + properties[n]); 1611 v = typeof v === 'string' ? v 1612 .replace(/^[\s\n]+|[\s\n]+$/g, '') 1613 .replace(/\r?\n\s+|\s+\r?\n/g, new_line) 1614 //.replace(/</g,'<') 1615 : ''; 1616 a = ''; 1617 1618 switch (n) { 1619 1620 case 'description': 1621 case 'summary': 1622 if (!v || /^[\s\n]*$/.test(v)) 1623 return; 1624 n = 'summary'; 1625 break; 1626 1627 case 'param': 1628 if (a = v.match(/^({([a-zA-Z_\d.$\|\s]+)}\s*)?([a-zA-Z_\d$]+|\[([a-zA-Z_\d.$]+)\])\s*(.*?)$/)){ 1629 var t = a[2].replace(/\s+/g, ''); 1630 v = a[5], a = ' name="' + (a[4] || a[3]) + '" type="' + t + '" optional="' + (!!a[4]) + '"'; 1631 1632 if (/integer/i.test(t)) 1633 a += ' integer="true"'; 1634 // from CeL.net.web 1635 if (/HTML([A-U][A-Za-z]{1,15})?Element/i.test(t)) 1636 a += ' domElement="true"'; 1637 }else 1638 a = ''; 1639 break; 1640 1641 case 'type': 1642 return; 1643 1644 case 'return': 1645 n += 's'; 1646 case 'returns': 1647 if (a = v.match(/^({([a-zA-Z_\d$.\|\s]+)})?(.*)$/)){ 1648 v = a[3].replace(/^[\s\n]+/g, ''); 1649 a = a[2].replace(/\s+/g, '') || properties.type; 1650 1651 a = a ? ' type="' + a + '"' : ''; 1652 1653 if (/integer/i.test(t)) 1654 a += ' integer="true"'; 1655 // from CeL.net.web 1656 if (/HTML([A-U][A-Za-z]{1,15})?Element/i.test(t)) 1657 a += ' domElement="true"'; 1658 }else 1659 a = ''; 1660 break; 1661 1662 default: 1663 } 1664 1665 if (v.indexOf(new_line) === -1 && a.indexOf(new_line) === -1) 1666 p.push('<' + n + a + (v ? '>' + v + '</' + n + '>' : '/>')); 1667 else{ 1668 p.push('<' + n + a + '>'); 1669 p = p.concat(v.split(new_line)); 1670 p.push('</' + n + '>'); 1671 } 1672 }; 1673 1674 for (n in properties) 1675 if (library_namespace.is_Array(V = properties[n])) 1676 for (i = 0, l = V.length; i < l; i++) 1677 t_p(V[i]); 1678 else 1679 t_p(V); 1680 1681 return p.length>1 ? p.join(new_line + ' /// ') + new_line 1682 + new_line : ''; 1683 }, 1684 /** 1685 * 從變數定義取得變數名。 1686 * 1687 * @param {String} _ 1688 * 變數定義 1689 * @inner 1690 * @ignore 1691 */ 1692 set_name = function(_) { 1693 name = properties.name; 1694 if (!name) { 1695 name = []; 1696 var i = origin_index, l; 1697 while (i > 0) 1698 if (/[;{})]\s*$/.test(l = code[--i].replace(/\/\/.*$/, ''))) 1699 if ((name = name.join(' ') 1700 // 除去註解後 1701 .replace(/\/\*(.*?)\*\//g, ' ')) 1702 // 已無註解的話 1703 .indexOf('*/') === -1){ 1704 _ = name.replace(/^\s*var(\s+|$)/, '') + _; 1705 break; 1706 } else 1707 name = [ l, name ]; 1708 else if(l) 1709 name.unshift(l); 1710 1711 //if(!i): Error! 1712 //if(_.match(/var/)) library_namespace.warn(name+'\n'+_); 1713 1714 name = properties.memberOf ? 1715 (_.replace(/[\s\n]+/g, '').indexOf(properties.memberOf + '.') === -1 ? 1716 properties.memberOf + '.' : '') 1717 + _ /* .replace(/^(.+)\./,'') */ 1718 : 'property' in properties ? 1719 latest_name ? latest_name + '.prototype.' + _.replace(/^(.+)\./, '') : '' 1720 : _; 1721 } 1722 1723 // 除去 space 1724 name = name.replace(/[\s\n]+/g, ''); 1725 }, 1726 handle_name = function() { 1727 var m = name 1728 .match(/^([a-zA-Z_$\d]+)\.[^.].+[^.]\.([a-zA-Z_$\d]+)$/); 1729 return m && m[1] === library_namespace.Class ? m[1] + '.' 1730 + m[2] + '=' + name : name; 1731 }; 1732 1733 for (i = 0; i < l; i++) { 1734 // 一行一行判斷 1735 // TODO: 提升效率 1736 line = code[origin_index = i]; 1737 1738 if (/^\s*\/\*\*/.test(line)) { 1739 // 處理 '/**' 之註解(這些是有意義的) 1740 properties = {}; 1741 // 都沒有 '@' 時,預設為 @description 1742 name = 'description'; 1743 tmp_code = []; 1744 various=[]; 1745 //library_namespace.log('' + line); 1746 while (i < l) { 1747 //library_namespace.log('' + line); 1748 tmp_code.push(line); 1749 1750 // 判別 1751 if (line.indexOf('*/') !== -1 || (m = line.match(/^\s+\*\s+@([_a-zA-Z\d\$.]+)(\s+([^\s].*)?\s*)?$/))) { 1752 // 設定 name = various 1753 various = various.join(new_line); 1754 if (name in properties) 1755 if (library_namespace.is_Array(properties[name])) 1756 properties[name].push(various); 1757 else 1758 properties[name] = [ properties[name], various ]; 1759 else 1760 properties[name] = various; 1761 1762 if (line.indexOf('*/') !== -1) 1763 break; 1764 1765 name = m[1], various = [ m[3] ]; 1766 1767 } else 1768 various.push((m = line.match(/^\s+\*\s+([^\s].+)$/)) ? m[1] : line.replace(/^(.*)\/\*\*/, '')); 1769 1770 line = code[++i]; 1771 } 1772 1773 //library_namespace.log('[' + i + ']' + '\n' + tmp_code.join('\n') + '\n' + line); 1774 if (m = line.match(/(.*?\*\/)/)) { 1775 line = line.replace(/(.*?)\*\//, ''); 1776 while (i < l 1777 && !/=\s*[^\s]|{/.test(line = line.replace( 1778 /\s*\/\/[^\n]*/g, '').replace( 1779 /\/\*((.|\n)*?)\*\//g, ''))) 1780 line += code[++i]; 1781 1782 // 初始化函式名 1783 name = ''; 1784 1785 /* 1786 * 註解處理完了,接下來是變數。先把整個定義區放到 line。 1787 * 這邊處理幾種定義法: 1788 * function name() {}; 1789 * var name = function(){}; 1790 * var name = new Function(); 1791 * var name = 123; 1792 */ 1793 while (!/^\s*function\s$/.test(line) && !/[=;,]/.test(line)) 1794 line += ' ' + code[++i]; 1795 1796 if (m = line.match(/^\s*function\s+([_a-zA-Z\d\$.]*)\s*\((.*)/)) { 1797 // function name() {}; 1798 set_name(m[1]); 1799 various = m[2]; 1800 while (i < l && various.indexOf(')') === -1) 1801 various += code[++i]; 1802 m = various.match(/^[^)]*/); 1803 tmp_code.push(handle_name() + '=function(' + m[0] + '){' 1804 + jsdoc_to_vsdoc() + '};'); 1805 1806 } else if (m = line 1807 .match(/^\s*(var\s+)?([_a-zA-Z\d\$.]+)\s*=\s*(.+)/)) { 1808 set_name(m[2]); 1809 various = m[3]; 1810 if (/^\s*function(\s+[_a-zA-Z\d\$]+)?\s*\(/.test(various)) { 1811 // var name = function(){}; 1812 while (i < l && various.indexOf(')') === -1) 1813 various += code[++i]; 1814 m = various.match(/^[^)]+\)/); 1815 tmp_code.push(handle_name() + '=' + m[0] + '{' + jsdoc_to_vsdoc() + '};'); 1816 1817 } else if (/^\s*new\s+Function\s*\(/.test(various)) { 1818 // var name = new Function(); 1819 if (m = various.match(/^\s*new\s+Function\s*\(.+\)\s*;?\s*$/)) { 1820 // TODO 1821 tmp_code.push(handle_name() + '=new Function("");'); 1822 } else 1823 tmp_code.push(handle_name() + '=new Function();'); 1824 1825 } else { 1826 // var name = 123; 1827 if (!properties.type) 1828 if (/^['"]/.test(various)) { 1829 properties.type = 'String'; 1830 } else if (!isNaN(various)) { 1831 properties.type = 'number'; 1832 } else if (/^(true|false)([\s;,]|$)/.test(various)) { 1833 properties.type = 'bool'; 1834 } else if (various.charAt(0) === '[') { 1835 properties.type = 'array'; 1836 } else if (various.charAt(0) === '{') { 1837 properties.type = 'object'; 1838 } else if (various.charAt(0) === '/') { 1839 properties.type = 'regexp'; 1840 } else if (/^regexp obj(ect)?$/.test(properties.type)) { 1841 properties.type = 'regexp'; 1842 } 1843 1844 //if (name === 'module_name'); 1845 1846 switch ((properties.type || '').toLowerCase()) { 1847 case 'string': 1848 m = various.replace(/\s*[,;]*\s*$/, ''); 1849 //library_namespace.log('['+m+']'); 1850 if (/^'[^\\']*'$/.test(m) 1851 || /^"[^\\"]*"$/.test(m)) { 1852 various = '=' + m + ';'; 1853 } else { 1854 various = '=""; // ' + various; 1855 } 1856 properties.type='String'; 1857 break; 1858 1859 case 'bool': 1860 case 'boolean': 1861 if (m = various.toLowerCase().match( 1862 /^(true|false)([\s,;]|$)/i)) { 1863 various = '=' + m[1] + ';'; 1864 } else { 1865 various = '=true; // ' + various; 1866 } 1867 properties.type='Boolean'; 1868 break; 1869 1870 case 'number': 1871 properties.type = 'Number'; 1872 case 'int': 1873 case 'integer': 1874 if (/int(eger)?/i.test(properties.type)) 1875 properties.type = 'Integer'; 1876 1877 if (!isNaN(various)) { 1878 various = '=' + various + ';'; 1879 } else { 1880 various = '=0; // ' + various; 1881 } 1882 break; 1883 1884 case 'array': 1885 various = '=' + '[];'; 1886 properties.type = 'Array'; 1887 break; 1888 1889 case 'object': 1890 if (various.charAt(0) === '{') { 1891 while (i < l) { 1892 if (various.lastIndexOf('}') !== -1) { 1893 m = various.slice(1, various.lastIndexOf('}')); 1894 if (m.lastIndexOf('/*') === -1 1895 || m.lastIndexOf('/*') < m 1896 .lastIndexOf('*/')) 1897 break; 1898 } 1899 various += '\n' + code[++i]; 1900 } 1901 m = various 1902 .replace(/\s*\/\/[^\n]*/g, '') 1903 .replace(/\/\*((.|\n)*?)\*\//g, '') 1904 .replace(/}(.*)$/,'}'); 1905 if (0 && m.length > 3) 1906 library_namespace.log(name + '\n' + m 1907 // + '\n'+v 1908 ); 1909 if (/^{([\s\n]*(('[^']*'|"[^"]*"|[_a-zA-Z\d\$.]+))[\s\n]*:('[^']*'|"[^"]*"|[\s\n\d+\-*\/()\^]+|true|false|null)+|,)*}/ 1910 .test(m)) 1911 various = '=' + various.replace(/}(.*)$/, '}') + ';'; 1912 else 1913 various = '=' + '{};'; 1914 } else 1915 various = '=' + '{};'; 1916 properties.type = 'Object'; 1917 break; 1918 1919 case 'regexp': 1920 if (/^\/.+\/$/.test(various)) 1921 various = '=' + various + ';'; 1922 else { 1923 various = '=' + '/^regexp$/; // ' + various; 1924 } 1925 properties.type = 'RegExp'; 1926 break; 1927 1928 default: 1929 // TODO: T1|T2|.. 1930 if (/^[_a-zA-Z\d\$.]/.test(various)) { 1931 // reference 1932 various = ';//' + (properties.type ? '[' + properties.type + ']' : '') 1933 + various; 1934 } else { 1935 // unknown code 1936 various = '; // ' 1937 + (properties.type ? '[' + properties.type + ']' : '') 1938 + various; 1939 } 1940 } 1941 1942 tmp_code.push((/^=/.test(various) ? '' : '//') + handle_name() + various); 1943 } 1944 } 1945 1946 if (name && !('ignore' in properties) && !('inner' in properties) && !('private' in properties)) { 1947 if (!('property' in properties)) 1948 // 定義最後一次變數名 1949 latest_name = name; 1950 1951 name = name.split(library_namespace.env.module_name_separator); 1952 1953 // 對可能的錯誤發出警告 1954 if (name[0] !== library_namespace.Class && !('deprecated' in properties)) 1955 library_namespace.warn(i + ': line [' + name.join(library_namespace.env.module_name_separator) + '] NOT initial as '+library_namespace.Class+'\n' 1956 + code.slice(i - 6, i + 6).join('\n')); 1957 1958 // 將變數定義設置到 ns 1959 var np = ns, nl = name.length - 1, n; 1960 for (m = 0; m < nl; m++) { 1961 n = name[m]; 1962 if (!(n in np)) 1963 // 初始設定 namespace 1964 np[n] = { 1965 'this': '' 1966 }; 1967 else if (!library_namespace.is_Object(np[n])) 1968 np[n] = { 1969 'this': np[n] 1970 }; 1971 np = np[n]; 1972 } 1973 1974 n = name[nl]; 1975 //if (n in np) library_namespace.log('get_various_from_code: get duplicate various: [' + name.join(library_namespace.env.module_name_separator) + ']'); 1976 1977 np[n] = tmp_code.join(new_line); 1978 } 1979 } 1980 } 1981 } 1982 1983 return ns; 1984 }; 1985 1986 1987 CeL.code.reorganize 1988 . 1989 /** 1990 * 把 get_various_from_code 生成的 namespace 轉成 code 1991 * @param {Object} ns root namespace 1992 * @param {String} [prefix] (TODO) prefix of root namespace 1993 * @param {Array} [code_array] inner use, please don't specify this value. 1994 * @return {String} code 1995 * @since 2009/12/20 14:51:52 1996 * @_memberOf _module_ 1997 */ 1998 get_code_from_generated_various = function (ns, prefix, code_array) { 1999 var _s = _.get_code_from_generated_various, i, return_text = 0; 2000 2001 if (!code_array) 2002 code_array = [], 2003 return_text = 1; 2004 2005 // 先處理 'this' 2006 if (prefix) { 2007 if (!/\.prototype$/.test(prefix)) 2008 if (i = ns['this']) { 2009 code_array.push(i); 2010 delete ns['this']; 2011 } else 2012 code_array.push('', 2013 '// null constructor for [' + prefix + ']', 2014 prefix + '=function(){};', 2015 prefix + '.prototype={};'); 2016 prefix += '.'; 2017 } else 2018 prefix = ''; 2019 2020 2021 for (i in ns) 2022 if (typeof ns[i] === 'string') 2023 code_array.push(ns[i]); 2024 else 2025 _s(ns[i], prefix + i, code_array); 2026 2027 return return_text ? 2028 code_array.join(library_namespace.env.new_line) 2029 //.replace(/[\r\n]+/g,library_namespace.env.new_line) 2030 : code_array; 2031 }; 2032 2033 2034 2035 return ( 2036 CeL.code.reorganize 2037 ); 2038 }; 2039 2040 //=================================================== 2041 2042 CeL.setup_module(module_name, code_for_including); 2043 2044 }; 2045