- Notifications
You must be signed in to change notification settings - Fork38
A feature rich code block preprocessing tool.
License
zswang/jdists
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
标签: jdists 教程
通常软件发布时会将源文件做一次「预处理」再编译成可执行文件,才发布到市场。
- 配置线上运行环境,如调试服务地址需变更为实现线上地址;
- 减少执行程序的大小,移除没有使用的代码或资源并压缩;
- 增加逆向工程的成本,给代码做混淆(包括改变标识符和代码结构),降低可读性;
- 移除或增加调试功能,关闭或开启一些特权后门。
一些 IDE 已在「编译」时集成了「预处理」功能。
jdists 是一款强大的代码块预处理工具。
通常就是注释或注释包裹的代码片段,用于表达各种各样的含义。
举个栗子
- TODO 注释,表示代码中待完善的地方
/* TODO 功能待开发 */
- wiredep 注释,表示引入 bower 组件依赖的 css 资源
<!-- bower:css --><linkrel="stylesheet"href="bower_components/css/bootstrap.css"/><!-- endbower -->
- jshint.js 顶部注释,表示版权声明
/*! * JSHint, by JSHint Community. * * This file (and this file only) is licensed under the same slightly modified * MIT license that JSLint is. It stops evil-doers everywhere: * * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) * ......... */
- jshint.js 另一部分注释,表示代码检查配置项
/*jshint quotmark:double *//*global console:true *//*exported console */
总之,本文所指「代码块」就是有特殊意义的注释。
指在代码编译之前,将代码文件按代码块粒度做一次编码或解析。
举个栗子,原本无效的代码片段,经过编码后变成了有效代码。
预处理前:
/*<jdists>console.log('Hello World!');</jdists>*/
预处理后:
console.log('Hello World!');
市面上有不少,这里只列两个比较典型的。
- 已被普遍使用的JSDoc,功能是将代码中的注释抽离成 API 文档。
/** * Represents a book. *@constructor *@param {string} title - The title of the book. *@param {string} author - The author of the book. */functionBook(title,author){}
- JSDev 是由 JSON 之父 Douglas Crockford 编写。jdists 与 JSDev 的功能类似,但 jdists 功能要复杂很多。
C command line example:
jsdev -comment"Devel Edition."<input>output test_expose enter:trace.enter exit:trace.exit unless:alert
#"auto" data-snippet-clipboard-copy-content="output = JSDEV(input, ["test_expose","enter:trace.enter","exit:trace.exit","unless:alert"] , ["Devel Edition."]);">
output=JSDEV(input,["test_expose","enter:trace.enter","exit:trace.exit","unless:alert"],["Devel Edition."]);
input:
// This is a sample file.functionConstructor(number){/*enter 'Constructor'*//*unless(typeof number !== 'number') 'number', "Type error"*/functionprivate_method(){/*enter 'private_method'*//*exit 'private_method'*/}/*test_exposethis.private_method = private_method;*/this.priv=function(){/*enter 'priv'*/private_method();/*exit 'priv'*/}/*exit "Constructor"*/}
output:
// Devel Edition.// This is a sample file.functionConstructor(number){{trace.enter('Constructor');}if(typeofnumber!=='number'){alert('number',"Type error");}functionprivate_method(){{trace.enter('private_method');}{trace.exit('private_method');}}{this.private_method=private_method;}this.priv=function(){{trace.enter('priv');}private_method();{trace.exit('priv');}}{trace.exit("Constructor");}}
lightly minified:
functionConstructor(number){functionprivate_method(){}this.priv=function(){private_method();}}
- 处理速度快,按需对代码块部分进行指定编码;
- 控制力更强,可以控制每个字符的变化;
- 不干扰编译器,编译器天然忽略注释。
- 不容易学习和记忆。
begin
还是start
,前缀还是后缀?
<!-- 乐居广告脚本 begin-->/* jshint ignore:start *//* TODO 待开发功能 */
- 是否存在闭合不明显。什么时候生效,什么时候失效?
/*jshint unused:true, eqnull:true*//*test_exposethis.private_method = private_method;*/
- 没有标准,不能跨语言。JSDev 和 JSDoc 不能用于其他主流语言,如 Python、Lua 等。
问题也就是:怎么定义、怎么处理、什么情况下触发。
本人拟订了一个基于「XML 标签」+「多行注释」的代码块规范:CBML
优势:
- 学习成本低,XML、多行注释都是大家熟知的东西;
- 标签是否闭合很明显;
- 支持多种主流编程语言。
处理的步骤无外乎就是:输入、编码、输出
经过解析 CBML 的语法树,获取tag
和attribute
两个关键信息。
如果tag
值为<jdists>
就开始按 jdists 的规则进行处理。
整个处理过程由四个关键属性决定:
import=
指定输入媒介export=
指定输出媒介encoding=
指定编码集合trigger=
指定触发条件
举个例子
/*<jdists export="template.js" trigger="@version < '1.0.0'">var template = /*<jdists encoding="base64,quoted" import="main.html?template" />*//*</jdists>
这里有两个代码块,还是一个嵌套结构
- 外层代码块属性
export="template.js"
指定内容导出到文件template.js
(目录相对于当前代码块所在的文件)。 - 外层代码块属性
trigger="@version < '1.0.0'"
指定命令行参数version
小于'1.0.0'
才触发。 - 内层代码块属性
encoding="base64,quoted"
表示先给内容做一次base64
编码再做一次quoted
即,编码成字符串字面量。
有两个触发条件:
- 当
tag
值为<jdists>
或者是被配置为jdists
标签 - 当属性
trigger=
表达式判断为true
由 tag 标识的代码区域
代码块主要有如下三种形式:
- 空内容代码块,没有包裹任何代码
/*<jdists import="main.js" />*/
- 有效内容代码块,包裹的内容是编译器会解析
/*<jdists encoding="uglify">*/functionformat(template,json){if(typeoftemplate==='function'){// 函数多行注释处理template=String(template).replace(/[^]*\/\*!?\s*|\s*\*\/[^]*/g,// 替换掉函数前后部分'');}returntemplate.replace(/#\{(.*?)\}/g,function(all,key){returnjson&&(keyinjson) ?json[key] :"";});}/*</jdists>*/
- 无效内容代码块,包裹的内容也在注释中
/*<jdists>console.log('version: %s', version);<jdists>*/
<jdists>
| 自定义
import=
指定输入媒介export=
指定输出媒介encoding=
指定编码集合trigger=
指定触发条件
&content
默认为 "&"file
文件> 如:>main.js
>index.html
#variant
变量> 如:>#name
>#data
[file]?block
readonly 代码块,默认file
为当前文件> 如:>filename?tagName
>filename?tagName[attrName=attrValue]
>filename?tagName[attrName=attrValue][attrName2=attrValue2]
@argument
readonly 控制台参数> 如:>@output
>@version
:environment
readonly 环境变量> 如:>:HOME
>:USER
[...]
、{...}
readonly 字面量> 如:>[1, 2, 3, 4]
>{title: 'jdists'}
'string'
readonly 字符串> 如:>'zswang'
触发器有两种表达式
- 触发器名列表与控制台参数
--trigger
是否存在交集,存在则被触发
当
$ jdists ... --trigger release
触发
<!--remove trigger="release"--><label>release</label><!--/remove-->
- 将变量、属性、环境变量表达式替换后的字面量结果是否为 true
当
$ jdists ... --version 0.0.9
触发
<!--remove trigger="@version < '1.0.0'"--><label>1.0.0+</label><!--/remove-->
可以参考项目中 processor 目录,中自带编码器的写法
举个栗子
varejs=require('ejs');/** * ejs 模板渲染 * *@param {string} content 文本内容 *@param {Object} attrs 属性 *@param {string} attrs.data 数据项 *@param {Object} scope 作用域 *@param {Function} scope.execImport 导入数据 *@param {Function} scope.compile 二次编译 jdists 文本 */module.exports=functionprocessor(content,attrs,scope){if(!content){returncontent;}varrender=ejs.compile(content);vardata;if(attrs.data){/*jslint evil: true */data=newFunction('return ('+scope.execImport(attrs.data)+');')();}else{data=null;}returnscope.compile(render(data));};
详情参考:jdists Scope
通过块导入
<!--remove--><script>/*<jdists encoding="base64">*/console.log('hello world!');/*</jdists>*/</script><!--/remove--><!--jdists><script src="data:application/javascript;base64,/*<jdists import="?[id=code]" />*/"></script></jdists-->
通过变量导入
<!--remove--><script>/*<jdists encoding="base64" export="#code">*/console.log('hello world!');/*</jdists>*/</script><!--/remove--><!--jdists><script src="data:application/javascript;base64,/*<jdists import="#code" />*/"></script></jdists-->
jdists 依赖 node v0.10.0 以上的环境
$ npm install jdists [-g]
Usage:jdists <input list> [options]Options:-r, --remove Remove block tag name list (default "remove,test")-o, --output Output file (default STDOUT)-v, --version Output jdists version-t, --trigger Trigger name list (default "release")-c, --config Path to config file (default ".jdistsrc")
varcontent=jdists.build(filename,{remove:'remove,debug',trigger:'release'});
https://github.com/zswang/jdists/issues
$ git clone https://github.com/zswang/jdists.git
$ npm install
$ npm test
$ npm run dist
$ npm run cover
[lib] --- 发布后的代码目录jdists.js --- jdists 业务代码scope.js --- jdists 作用域[processor] --- 预制编码器[processor-extend] --- 未预制的编码器,可能会常用的[src] --- 开发期代码[test] --- 测试目录[fixtures] --- 测试用例test.js --- 测试调度文件index.js --- jdists 声明cli.js --- jdists 控制台
About
A feature rich code block preprocessing tool.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.