├── test └── ut │ ├── file │ ├── e.js │ ├── embeded1.tpl │ ├── embeded2.tpl │ └── embeded3.tpl │ └── preprocessor-extlang.js ├── package.json ├── README.md └── index.js /test/ut/file/e.js: -------------------------------------------------------------------------------- 1 | console.log("extLang_TagMatching_test"); -------------------------------------------------------------------------------- /test/ut/file/embeded1.tpl: -------------------------------------------------------------------------------- 1 | {%script%}__inline("./e.js"){%/script%} -------------------------------------------------------------------------------- /test/ut/file/embeded2.tpl: -------------------------------------------------------------------------------- 1 | {%script %}__inline("./e.js"){%/script%} -------------------------------------------------------------------------------- /test/ut/file/embeded3.tpl: -------------------------------------------------------------------------------- 1 | {%script charset="UTF-8"%}__inline("./e.js"){%/script%} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fis-preprocessor-extlang", 3 | "version": "0.0.9", 4 | "description": "fis-preprocessor-extlang", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/xiangshouding/fis-preprocessor-extlang.git" 12 | }, 13 | "keywords": [ 14 | "fis" 15 | ], 16 | "author": "xiangshouding", 17 | "license": "MIT", 18 | "readmeFilename": "README.md", 19 | "gitHead": "9f228968f9f61685dfce1c37d10dc217f6d94c3c" 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fis-preprocessor-extlang 2 | ======================== 3 | 4 | 支持使用Smarty script, style 插件的JavaScript的语言扩展 5 | 6 | {%script%} 7 | require('./a.js'); 8 | __inline('./b.js'); 9 | var a = __uri('./c.js'); 10 | //blabla 11 | {%/script%} 12 | 13 | {%style%} 14 | @import url(./a.css?__inline); 15 | {%/style%} 16 | 17 | 使用 18 | ==== 19 | 20 | //install 21 | npm install -g fis-preprocessor-extlang 22 | 23 | 24 | //config 25 | vi /fis-conf.js 26 | 27 | fis.merge.config({ 28 | modules: { 29 | preprocessor: { 30 | tpl: "extlang" 31 | } 32 | }, 33 | .... 34 | }); 35 | -------------------------------------------------------------------------------- /test/ut/preprocessor-extlang.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fis = require('../../../fis-kernel/fis-kernel.js'), 4 | _ = fis.util, 5 | file = fis.file, 6 | expect = require('chai').expect, 7 | fs = require("fs"); 8 | var root = __dirname + '/file'; 9 | var extlang = require("../../index.js"); 10 | describe('compile(path, debug)', function () { 11 | var tempfiles = []; 12 | 13 | before(function(){ 14 | fis.project.setProjectRoot(root); 15 | fis.project.setTempRoot(root+'/target/'); 16 | }); 17 | 18 | afterEach(function(){ 19 | tempfiles.forEach(function(f){ 20 | _.del(root+'/target/'); 21 | }); 22 | }); 23 | 24 | /** 25 | *extlang中extHtml对标签{%script ...%}...{%/script%}的匹配验证 26 | * 以下三个例子 27 | * */ 28 | it('{%script%}_TagMatching',function(){ 29 | // {%script%}...{%/script%} 30 | var f = file(__dirname+'/file/embeded1.tpl'); 31 | tempfiles.push(f); 32 | 33 | var content = f.getContent() , 34 | conf_ = {}; 35 | var c = extlang(content,f,conf_); 36 | 37 | expect(c).to.equal('{%script%}'+fis.compile.lang.embed.ld+'\"./e.js\"'+fis.compile.lang.embed.rd+'{%/script%}'); 38 | }); 39 | 40 | it('{%script %}_TagMatching',function(){ 41 | //{%script %}...{%/script%} 42 | var f = file(__dirname+'/file/embeded2.tpl'); 43 | tempfiles.push(f); 44 | 45 | var content = f.getContent() , 46 | conf_ = {}; 47 | var c = extlang(content,f,conf_); 48 | 49 | expect(c).to.equal('{%script %}'+fis.compile.lang.embed.ld+'\"./e.js\"'+fis.compile.lang.embed.rd+'{%/script%}'); 50 | }); 51 | 52 | it('{%script ...%}_TagMatching',function(){ 53 | //{%script ...%}...{%/script%} 54 | var f = file(__dirname+'/file/embeded3.tpl'); 55 | tempfiles.push(f); 56 | 57 | var content = f.getContent() , 58 | conf_ = {}; 59 | var c = extlang(content,f,conf_); 60 | 61 | expect(c).to.equal('{%script charset="UTF-8"%}'+fis.compile.lang.embed.ld+'\"./e.js\"'+fis.compile.lang.embed.rd+'{%/script%}'); 62 | }); 63 | 64 | 65 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * fis 3 | * http://fis.baidu.com 4 | */ 5 | 6 | 'use strict' 7 | 8 | var ldraw, rdraw, ld, rd; 9 | 10 | function pregQuote (str, delimiter) { 11 | // http://kevin.vanzonneveld.net 12 | return (str + '').replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&'); 13 | } 14 | 15 | //"abc?__inline" return true 16 | //"abc?__inlinee" return false 17 | //"abc?a=1&__inline"" return true 18 | function isInline(info){ 19 | return /[?&]__inline(?:[=&'"]|$)/.test(info.query); 20 | } 21 | 22 | //analyse [@require id] syntax in comment 23 | function analyseComment(comment, map){ 24 | var reg = /(@require\s+)('[^']+'|"[^"]+"|[^\s;!@#%^&*()]+)/g; 25 | return comment.replace(reg, function(m, prefix, value){ 26 | return prefix + map.require.ld + value + map.require.rd; 27 | }); 28 | } 29 | 30 | //expand javascript 31 | //[@require id] in comment to require resource 32 | //__inline(path) to embedd resource content or base64 encodings 33 | //__uri(path) to locate resource 34 | //require(path) to require resource 35 | function extJs(content, map){ 36 | var reg = /"(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|(\/\/[^\r\n\f]+|\/\*[\s\S]+?(?:\*\/|$))|\b(__inline|__uri|require)\s*\(\s*("(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*')\s*\)/g; 37 | return content.replace(reg, function(m, comment, type, value){ 38 | if(type){ 39 | switch (type){ 40 | case '__inline': 41 | m = map.embed.ld + value + map.embed.rd; 42 | break; 43 | case '__uri': 44 | m = map.uri.ld + value + map.uri.rd; 45 | break; 46 | case 'require': 47 | m = 'require(' + map.require.ld + value + map.require.rd + ')'; 48 | break; 49 | } 50 | } else if(comment){ 51 | m = analyseComment(comment, map); 52 | } 53 | return m; 54 | }); 55 | } 56 | 57 | //expand css 58 | //[@require id] in comment to require resource 59 | //[@import url(path?__inline)] to embed resource content 60 | //url(path) to locate resource 61 | //url(path?__inline) to embed resource content or base64 encodings 62 | //src=path to locate resource 63 | function extCss(content, map){ 64 | var reg = /(\/\*[\s\S]*?(?:\*\/|$))|(?:@import\s+)?\burl\s*\(\s*("(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|[^)}]+)\s*\)(\s*;?)|\bsrc\s*=\s*("(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|[^\s}]+)/g; 65 | var callback = function(m, comment, url, last, filter){ 66 | if(url){ 67 | var key = isInline(fis.util.query(url)) ? 'embed' : 'uri'; 68 | if(m.indexOf('@') === 0){ 69 | if(key === 'embed'){ 70 | m = map.embed.ld + url + map.embed.rd + last.replace(/;$/, ''); 71 | } else { 72 | m = '@import url(' + map.uri.ld + url + map.uri.rd + ')' + last; 73 | } 74 | } else { 75 | m = 'url(' + map[key].ld + url + map[key].rd + ')' + last; 76 | } 77 | } else if(filter) { 78 | m = 'src=' + map.uri.ld + filter + map.uri.rd; 79 | } else if(comment) { 80 | m = analyseComment(comment, map); 81 | } 82 | return m; 83 | }; 84 | return content.replace(reg, callback); 85 | } 86 | 87 | // html 88 | //{%script ...%}...{%/script%} to analyse as js 89 | function extHtml(content, map, conf){ 90 | var reg = new RegExp('('+ld+'script(?:(?=\\s)[\\s\\S]*?["\'\\s\\w]'+rd+'|'+rd+'))([\\s\\S]*?)(?='+ld+'\\/script'+rd+'|$)|('+ld+'style(?:(?=\\s)[\\s\\S]*?["\'\\s\\w\\-]'+rd+'|'+rd+'))([\\s\\S]*?)(?='+ld+'\\/style\\s*'+rd+'|$)', 'ig'); 91 | content = content.replace(reg, function(m, $1, $2, $3, $4){ 92 | if ($1) { 93 | m = $1 + extJs($2, map); 94 | } else if($3){ 95 | m = $3 + extCss($4, map); 96 | } 97 | return m; 98 | }); 99 | 100 | return extSmarty(content, map, conf); 101 | } 102 | 103 | function extSmarty(content, map, conf) { 104 | var reg = new RegExp('(' + ld + '\\*[\\s\\S]*?(?:\\*' + rd + '|$))|(?:' + ld + '(extends|widget|require|uri|html)(.+?)' + rd + ')', 'ig'); 105 | 106 | content = content.replace(reg, function(m, comments, directive, params) { 107 | if (!comments && params) { 108 | switch (directive) { 109 | case 'extends': 110 | params = params.replace(/\sfile\s*=\s*('|")(.+?)\1/ig, function(_, quote, value) { 111 | return ' file=' + map.tpl.ld + quote + value + quote + map.tpl.rd; 112 | }); 113 | break; 114 | 115 | case 'html': 116 | params = params.replace(/\sframework\s*=\s*('|")(.+?)\1/ig, function(_, quote, value) { 117 | return ' framework=' + map.id.ld + quote + value + quote + map.id.rd; 118 | }); 119 | break; 120 | 121 | default: 122 | params = params.replace(/\sname\s*=\s*('|")(.+?)\1/ig, function(_, quote, value) { 123 | return ' name=' + map.id.ld + quote + value + quote + map.id.rd; 124 | }); 125 | break; 126 | } 127 | 128 | m = ldraw + directive + params + rdraw; 129 | } 130 | 131 | 132 | return m; 133 | }); 134 | 135 | return content; 136 | } 137 | 138 | module.exports = function (content, file, conf) { 139 | ldraw = conf.left_delimiter || fis.config.get('settings.smarty.left_delimiter') || fis.config.get('settings.template.left_delimiter') || '{%'; 140 | rdraw = conf.right_delimiter || fis.config.get('settings.smarty.right_delimiter') || fis.config.get('settings.template.right_delimiter') || '%}'; 141 | ld = pregQuote(ldraw); 142 | rd = pregQuote(rdraw); 143 | 144 | // 扩展两种语法 145 | var map = fis.compile.lang; 146 | if (!map['id'] || !map['tpl']) { 147 | var LD = '<<<', RD = '>>>'; 148 | 149 | ['id', 'tpl'].forEach(function(key) { 150 | map[key] = { 151 | ld: LD + key + ':', 152 | rd: RD 153 | }; 154 | }); 155 | } 156 | 157 | if (file.isHtmlLike) { 158 | return extHtml(content, fis.compile.lang, conf) 159 | .replace(/\<\<\<(id|tpl)\:([\s\S]+?)\>\>\>/ig, function(_, key, value) { 160 | var info = fis.uri.getId(value, file.dirname); 161 | 162 | if (info.file) { 163 | var value = info.id; 164 | 165 | if (key === 'tpl') { 166 | value = value.replace(':', '/'); 167 | } 168 | 169 | return info.quote + value + info.quote; 170 | } 171 | 172 | return value; 173 | }); 174 | } 175 | }; 176 | --------------------------------------------------------------------------------