diff --git a/.travis.yml b/.travis.yml index 9e7edefbf..4dd33a33c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,30 @@ language: node_js - os: - - linux - +- linux node_js: - - "0.10" - - "0.12" - - "4" - +- '0.10' +- '0.12' +- '4' +- '6' env: global: + - GH_REF: git.duapp.com/appidenoe6p61ew/ - secure: jKTCY7zQ/8YsHjfTYOkzeEAH4WASb1Nt92dXvMgAzDB2/GmGlmRbp2wO/3/SABbHA7oow3Ocniayl3wp29WNkzffylnOC6g9ThFekTqBjdh/gpCDK/MBjJ+J/ZhIjhGjKGSddicyVyVhsEaO1ZlxSMUnLjUtAEkYAgjtxWD0QJnoke7JjKgqKSwKcK0nisJ2hbHMKEGj5J3IdeMPq4db66ofZnkNqPkGdG1irVmRVksTtC911eqq8EaSZuwbp8TaVrmF3JsVshoVbDTrIHrGjCM98YNi54W1gPhPHuKupENNAJcKAA6IRiWXG3frCAZJDkLpsj+RweGDLVgNpQfdrqi/K1NCfnENG4xfkAzW8vBl22TQmIysbVo6iMgtlGkYq4dgw6T3MTnVS5utqbqd0VMDRpoPZfjhZv0r+akwdS/6lgno6/T3bLAqlNThqCuhIdK7VMzgQ0PCkXEWEbF5XXZjjs8QwESqPImtP9ZXQ8oYaOts+QIxX7kHDxoLZWJ14vsuw1cIYM5gCIEUmEeSzbGH6SrU/USn+QU4HYgdNWsfkjraEli58ThrS1xb9/soF3at1hpAZWPaIH32bqL6XfQrPFwiF6VLu5C1g3tdEFox+ylArVOMAB6FUl9xonKyGRAkVYbRi9sGI/JpTOMYTbqiocb/qviKPTHv4l2/m5o= + - secure: gPdCRj/7HpM7whMkm4h9eB22JZ47ANluae9nSRH9aExuJnutlic/4SKjnbDrkczo5/+y1RU9PoLg4kEyeE4se2jp3z5PDUb2Y0OYqeV30YYV7zMjLM6B+jpvZFb9SD9Gy2Yo0kBy79yDZ5ArRCN4UBoSlO4YRMy1tVq2LoNuw57o8nesZ9Q8VVLJp9vH3kcqo600w25m3GyRGfkI5SV02g293UUL5w2XxdMuKATCdbcPCOW09xBFh1Kg99uGduYRIQRIW7aIhZuWrEckD9dO7cmZhI1czC3rB1jtZLIHkIpE2Uv2TVYMYfHqE9B3yA88tvI1OadmGefNAiCJQD3nr+d/NfqQ7g8mOOgi8xCvR6VM4NUIfw2xz+QNGjduKYn8R/loQfW3P5ZQTojYKYDVALlYU1lzW6XpndkgR0KzTVjNRVXur5c1X71Cs7JBLeLDHabqByjHaInVhcNLNXNyowJcU5L6qkGnYs9AOgVqwpyDwRWt51RQNwOVMBxeOFMPtyYR0AIw0BinBl/u22K+wNOX56FGLKewksqnVrzzuf1IYyrKbSpN78s42aDqEppAeoWZH5JMplOo0N6NF1kPj3PP8isFo4BFgOxvuCvZ0olkhAtufQWqqktrtVYS+aYWmYjpqZT5J8rz156XCLVJK9snaasPwX6oSkYBnr6ZFNE= + - secure: vLzBXMNwQupoavD880TqnF799azdeTKXQgKOB382TG/vovKTS+YiX5DqPXkDoRTrarSuWQHUx6iTaT/ehTwWz3Bpmf5lKDC1q6Kt4h/hxTseESlMvZI8XBHh3LihdvFcOqzPOcdd43ut+oqY8jJQxUD8fy1Yd629h8ADSsZyfVwWfrY9I2IYZYFR5FBqrroAIDIOSyWGocIezWxc6S+swMF6bn0B3SXnu0ISVLQSo3gyeWOAnDQYZ7ghuR19KTfWR+Ww+GPY1jSad9s6dqEq046aLOb7TD/RWzzb5IJxdQA4CErZg9ITnfa2cl6lTZa6mAXFwmFwcq9UFyLiZMwjXoUd4suXU+MuMCAbsFfXUYNYruMzIvuCCkVq8lQ/N2Ah9gWQZhisFnAsuDWLo94IH7RyHHPD2SSLRs8ZM5duPT9Kh/5E8LjjU7AHClinBvVc4gw49ZxxXWRxldAS7WnMRa0meg/b4Hrawz/PROcmmjSqbb+40/LL3x6YCw2wi+VQkNZY8AloKuVnohowJZvj/a3ufZFEDUI3rll2Q6XvdFLlHwUsx+eZlstxNodDOYPm4S9LUekapHo4+EXX9GhxrcXMSEZFrQPqIZpCNae7ML7gJrl6yJ02oNltAYR4+mkWuQYpAtZtRDQjytvrmJ5+zhdPoS4U0hFBIdkwVSON3fk= install: - npm install before_script: - - sudo apt-get update - - sudo apt-get install apache2 - - sudo apt-get install php5 - - sudo ln -s $(pwd) /var/www/fis3 - - sudo service apache2 restart +- sudo apt-get update +- sudo apt-get install apache2 +- sudo apt-get install php5 +- sudo ln -s $(pwd) /var/www/fis3 +- sudo service apache2 restart script: -- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && sh ./release-doc.sh || true' -- 'npm run-script test-travis' +- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && bash ./release-doc.sh || true' +- npm run-script test-travis after_script: -- 'npm install coveralls@2.10.0 && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js' +- npm install coveralls@2.10.0 && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js cache: directories: - node_modules @@ -32,4 +33,4 @@ branches: - master - test-more-platform sudo: - - true +- true diff --git a/ISSUE_TEMPLATE b/ISSUE_TEMPLATE new file mode 100644 index 000000000..9b137d580 --- /dev/null +++ b/ISSUE_TEMPLATE @@ -0,0 +1,7 @@ +* **操作系统**: +* **Node版本**: +* **FIS版本**: +* **解决方案**: +* **依赖插件**: + + diff --git a/README.md b/README.md index f7c098785..d41f3459d 100644 --- a/README.md +++ b/README.md @@ -4,23 +4,30 @@ ![](https://img.shields.io/npm/v/fis3.svg) ![](https://img.shields.io/npm/dm/fis3.svg) [![Build Status](https://travis-ci.org/fex-team/fis3.svg?branch=master)](https://travis-ci.org/fex-team/fis3) [![Coverage Status](https://coveralls.io/repos/fex-team/fis3/badge.svg?branch=master&service=github)](https://coveralls.io/github/fex-team/fis3?branch=master) +[![](https://david-dm.org/fex-team/fis3/status.svg)](https://david-dm.org/fex-team/fis3) FIS3 面向**前端**的**工程构建系统**。解决前端工程中性能优化、资源加载(异步、同步、按需、预加载、依赖管理、合并、内嵌)、模块化开发、自动化工具、开发规范、代码部署等问题。 > 如果对FIS先有些了解,但理解不深的,可试着带着这句话去看文档
> FIS3 会在配置文件中给文件添加相应属性,用于控制文件的编译、合并等各种操作;文件属性包括基本属性和插件属性,[详细请参考](https://github.com/fex-team/fis3/blob/master/doc/docs/api/config-props.md#文件属性) -``` +```bash npm install -g fis3 ``` +**如果 Node 版本低于 4.x 请安装旧版本** + +```bash +npm install -g fis3@3.4.36 +``` + ## 文档 快速入门、配置、插件开发以及原理等文档 [doc/docs/INDEX.md](doc/docs/INDEX.md) ## 例子 -``` +```bash mkdir my-proj cd my-proj fis3 init @@ -73,12 +80,12 @@ https://github.com/fex-team/fis3-demo ## 常用插件 -###优化类(插件属性:optimizer) +### 优化类(插件属性:optimizer) - [fis-optimizer-uglify-js](https://www.npmjs.com/package/fis-optimizer-uglify-js) UglifyJS2 压缩插件 - [fis-optimizer-clean-css](https://www.npmjs.com/package/fis-optimizer-clean-css) CleanCss 压缩插件 - [fis-optimizer-png-compressor](https://www.npmjs.com/package/fis-optimizer-png-compressor) PNG 压缩插件 -###预处理类(插件属性:parser) +### 预处理类(插件属性:parser) - [fis-parser-less](https://www.npmjs.com/package/fis-parser-less) less 解析插件 -- [fis-parser-sass](https://www.npmjs.com/package/fis-parser-sass) sass / scss 解析插件 +- [fis-parser-node-sass](https://www.npmjs.com/package/fis-parser-node-sass) sass / scss 解析插件 - [fis-parser-handlebars](https://www.npmjs.com/package/fis-parser-handlebars) handlebars 解析插件 diff --git a/bin/fis.js b/bin/fis.js index 6983bee6c..f0061294a 100755 --- a/bin/fis.js +++ b/bin/fis.js @@ -25,8 +25,13 @@ cli.launch({ } else { fis = require(env.modulePath); } - fis.set('system.localNPMFolder', path.join(env.cwd, 'node_modules/fis3')); - fis.set('system.globalNPMFolder', path.dirname(__dirname)); + + process.title = this.name +' ' + process.argv.slice(2).join(' ') + ' [ ' + env.cwd + ' ]'; + + // 配置插件查找路径,优先查找本地项目里面的 node_modules + // 然后才是全局环境下面安装的 fis3 目录里面的 node_modules + fis.require.paths.unshift(path.join(env.cwd, 'node_modules')); + fis.require.paths.push(path.join(path.dirname(__dirname), 'node_modules')); fis.cli.name = this.name; fis.cli.run(argv, env); }); diff --git a/doc/docs/INDEX.md b/doc/docs/INDEX.md index 9ba9c9020..5df775724 100644 --- a/doc/docs/INDEX.md +++ b/doc/docs/INDEX.md @@ -44,7 +44,7 @@ - [解决方案封装](./lv3.md#解决方案封装) - [基于Smarty的解决方案](./lv3.md#基于Smarty的解决方案) - [基于纯PHP的解决方案](./lv3.md#基于纯PHP的解决方案) - - [基于Laveral的解决方案](./lv3.md#基于Laveral的解决方案) + - [基于Laravel的解决方案](./lv3.md#基于Laravel的解决方案) - 接口文档 - [命令行](./api/command.md) - [配置](./api/config.md) @@ -54,5 +54,7 @@ - [glob](./api/config-glob.md) - [内置插件及配置](./api/config-system-plugin.md) - [自定义插件](./api/dev-plugin.md) -- [mock 假数据模拟](./node-mock.md) - [FIS2 到 FIS3](./fis2-to-fis3.md) +- [资源合并](./pack.md) +- [mock 假数据模拟](./node-mock.md) +- [常用的插件列表](./common-plugin.md) diff --git a/doc/docs/api/config-glob.md b/doc/docs/api/config-glob.md index 9be0301cb..9a73c3cd5 100644 --- a/doc/docs/api/config-glob.md +++ b/doc/docs/api/config-glob.md @@ -52,11 +52,11 @@ FIS3 中支持的 glob 规则,FIS3 使用 [node-glob](https://github.com/isaac release: '/b/$1' }); ``` - + ### 捕获分组 - + 使用 `node-glob` 捕获的分组,可以用于其他属性的设定,如 `release`, `url`, `id` 等。使用的方式与正则替换类似,我们可以用 $1, $2, $3 来代表相应的捕获分组。其中 $0 代表的是 match 到的整个字符串。 - + ```js fis.match('/a/(**.js)', { release: '/b/$1' // $1 代表 (**.js) 匹配的内容 @@ -136,6 +136,9 @@ FIS3 中支持的 glob 规则,FIS3 使用 [node-glob](https://github.com/isaac }); ``` + 6. `*.html:inline-style` 用来匹配命中的 html 文件中的内联样式。可以配置些 auto prefix 之类的插件。 + 7. `*.html:scss` 用来命中 html 文件中的 scss 部分,具体请参考 [fis3-demo](https://github.com/fex-team/fis3-demo) 中的 [use-xlang](https://github.com/fex-team/fis3-demo/tree/master/use-xlang) + ## 注意事项 > fis3 小于 3.3.4 的版本需要注意, 3.3.4 以上的版本已修复此问题。 diff --git a/doc/docs/api/config-props.md b/doc/docs/api/config-props.md index c248896ed..e2e6401e0 100644 --- a/doc/docs/api/config-props.md +++ b/doc/docs/api/config-props.md @@ -39,6 +39,8 @@ var DEFAULT_SETTINGS = { ```js fis.set('project.charset', 'gbk'); ``` + + > 使用 charset 编码需要使用[encoding](https://github.com/fex-team/fis3-deploy-encoding)插件发布编译结果 ### project.md5Length @@ -130,6 +132,8 @@ fis3 以文件属性控制文件的编译合并以及各种操作;文件属性 - [extras](#extras) - [requires](#requires) - [useSameNameRequire](#useSameNameRequire) +- [useCache](#useCache) +- [useCompile](#useCompile) #### release * 解释:设置文件的产出路径。默认是文件相对项目根目录的路径,以 / 开头。该值可以设置为 false ,表示为不产出(unreleasable)文件。 @@ -259,6 +263,8 @@ fis.match('/mod.js', { charset: 'gbk' }); ``` + + > 使用 charset 编码需要使用[encoding](https://github.com/fex-team/fis3-deploy-encoding)插件发布编译结果 #### isHtmlLike * 解释:指定对文件进行 [html](../user-dev/extlang.md#html) 相关语言能力处理 @@ -384,6 +390,30 @@ fis.match('/mod.js', { }); ``` +#### useCache +* 注释: 文件是否使用编译缓存 +* 值类型:`bool` +* 默认值: `true` +* 说明:当设置使用编译缓存,每个文件的编译结果均会在磁盘中保存以供下次编译使用。设置为 `false` 后,则该文件每次均会被编译。 + + ```js + fis.match('**.html', { + useCache: false + }); + ``` + +#### useCompile +* 注释: FIS是否对文件进行编译 +* 值类型:`bool` +* 默认值: `true` +* 说明:设置为 `false` 后文件会通过FIS发布,但是FIS不对文件做任何修改 + + ```js + fis.match('**.html', { + useCompile: false + }); + ``` + ### 插件属性 插件属性决定了匹配的文件进行哪些插件的处理; @@ -426,7 +456,7 @@ fis.match('*.less', { ```js fis.match('*.sass', { - parser: fis.plugin('sass'), //启用fis-parser-sass插件 + parser: fis.plugin('node-sass'), //启用fis-parser-node-sass插件 rExt: '.css' }); ``` @@ -438,7 +468,7 @@ fis.match('*.sass', { ```js fis.match('*.{css,less}', { - paser: fis.plugin('image-set') + preprocessor: fis.plugin('image-set') }); ``` diff --git a/doc/docs/api/config.md b/doc/docs/api/config.md index 259e50465..6467c34e5 100644 --- a/doc/docs/api/config.md +++ b/doc/docs/api/config.md @@ -90,7 +90,7 @@ fis.match('a.js', { optimizer: null }) ``` -这样的设置下,当 `a.js` 处理使还是会被调用压缩器进行压缩; +这样的设置下,当 `a.js` 处理时还是会被调用压缩器进行压缩; ### ::package diff --git a/doc/docs/api/dev-plugin.md b/doc/docs/api/dev-plugin.md index 8520c6264..6af019c05 100644 --- a/doc/docs/api/dev-plugin.md +++ b/doc/docs/api/dev-plugin.md @@ -11,7 +11,7 @@ FIS3 是以 File 对象为中心构建编译的,每一个 File 都要经历编 在编译阶段,文件是单文件进行编译的,这个阶段主要是对文件内容的编译分析;这个阶段分为 `lint`、`parser`、`preprocessor`、`postprocessor`、`optimizer` 等插件扩展点。 -对于这些插件扩展点,可详见文档 [单文件编译流程][] +对于这些插件扩展点,可详见文档 [单文件编译流程](/fis3/docs/build.html#%E5%8D%95%E6%96%87%E4%BB%B6%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B) 其扩展点插件接口比较简单; @@ -28,11 +28,11 @@ module.exports = function (content, file, settings) { }; ``` -为了搞清楚哪些功能用那种类型的插件去实现比较好,建议详细阅读[单文件编译流程][]这篇文档。 +为了搞清楚哪些功能用那种类型的插件去实现比较好,建议详细阅读[单文件编译流程](/fis3/docs/build.html#%E5%8D%95%E6%96%87%E4%BB%B6%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B) 这篇文档。 fis 的插件是以 NPM 包的形式提供的,这将意味着 fis 的插件都是一个 NPM 包,并且最终也需要发布到 NPM 平台上。在开始之前你需要了解 node 是如何加载一个 NPM 包的 https://nodejs.org/api/modules.html -FIS3 不再强制用户必须把插件(一个 NPM 包)进行全局安装,可把包安装到 fis-conf.js 同目录下(项目目录)或者某一个父目录,这个遵循 node 加载一个包的规范即可。 +FIS3 不再强制用户必须把插件(一个 NPM 包)进行全局安装,可把插件安装到项目根目录 (fis-conf.js 所在目录或 --root 指定的目录),这个遵循 node 加载一个包的规范即可。 ``` my-proj/ @@ -94,7 +94,7 @@ fis.match('*.js', { ### 打包阶段插件 -原理请详细参考文档 [构建流程][]。到打包阶段,所有的文件都经过了单文件处理,该压缩的已经被压缩,该预编译的也进行了预编译。这个阶段主要实现一些共性的功能,比如打包合并。所以插件接口也不太一样了。 +原理请详细参考文档 [构建流程](/fis3/docs/build.html#%E6%9E%84%E5%BB%BA%E6%B5%81%E7%A8%8B)。到打包阶段,所有的文件都经过了单文件处理,该压缩的已经被压缩,该预编译的也进行了预编译。这个阶段主要实现一些共性的功能,比如打包合并。所以插件接口也不太一样了。 ```js /** @@ -113,7 +113,7 @@ module.exports = function (ret, conf, settings, opt) { } ``` -跟编译时打包一样,也可项目本地开发或者是直接写到 fis-conf.js 中。参考 [打包阶段插件](./config-api.md#打包阶段插件)。其配置方式与单文件编译阶段插件配置方式不同。由于 packager 时所有文件都在处理之列,所以需要通过以下方式进行配置; +跟编译时打包一样,也可项目本地开发或者是直接写到 fis-conf.js 中。参考 [打包阶段插件](/fis3/docs/api/config-api.html#打包阶段插件)。其配置方式与单文件编译阶段插件配置方式不同。由于 packager 时所有文件都在处理之列,所以需要通过以下方式进行配置; ```js fis.match('::package', { diff --git a/doc/docs/beginning/debug.md b/doc/docs/beginning/debug.md index d85f57028..25a09adf5 100644 --- a/doc/docs/beginning/debug.md +++ b/doc/docs/beginning/debug.md @@ -68,6 +68,9 @@ fis3 release -wL 当我们开发项目后,需要发布到测试机(联调机),一般可以通过如 SMB、FTP 等上传代码。FIS3 默认支持使用 HTTP 上传代码,首先需要在测试机部署上传接收脚本(或者服务),这个脚本非常简单,现在给出了 [php 的实现版本](https://github.com/fex-team/fis-command-release/blob/master/tools/receiver.php),可以把它放到测试机上某个 Web 服务根目录,并且配置一个 url 能访问到即可。 +> 注意:**此代码存在很大的安全隐患,没有做任何安全考虑,请不要部署到线上服务。** +> 百度内部请使用:http://agroup.baidu.com/fis/md/article/196978 + > 示例脚本是 php 脚本,测试机 Web 需要支持 PHP 的解析
> 如果需要其他语言实现,请参考这个 php 脚本实现,如果嫌麻烦,我们提供了一个 node 版本的[接收端](https://github.com/fex-team/receiver) diff --git a/doc/docs/beginning/install.md b/doc/docs/beginning/install.md index 443d7e1f4..061768a6a 100644 --- a/doc/docs/beginning/install.md +++ b/doc/docs/beginning/install.md @@ -6,7 +6,7 @@ 详细过程参考官网 https://nodejs.org -> Node **版本要求** 0.8.x,0.10.x, 0.12.x,4.x,不在此列表中的版本不予支持。最新版本 node 支持会第一时间跟进,支持后更新支持列表。 +> Node **版本要求** 0.8.x,0.10.x, 0.12.x,4.x,6.x,不在此列表中的版本不予支持。最新版本 node 支持会第一时间跟进,支持后更新支持列表。 - Ubuntu 用户使用 `apt-get` 安装 node 后,安装的程序名叫 `nodejs`,需要软链成 `node` - Windows 用户安装完成后需要在 CMD 下确认是否能执行 node 和 npm @@ -22,7 +22,7 @@ npm install -g fis3 - 如果已经安装了 [FIS](https://github.com/fex-team/fis),也执行上面的命令进行安装,FIS3 和 FIS 是不同的构建工具,向下无法完全兼容。如果要从 FIS 迁移到 FIS3,请参考文档 [FIS 升级 FIS3](../fis2-to-fis3.md) - 如果 npm 长时间运行无响应,推荐使用 [cnpm](http://npm.taobao.org/) 来安装 -安装完成后执行 `fis3 -v` 判断是否安装成功,如果安装成功,则显示如下信息: +安装完成后执行 `fis3 -v` 判断是否安装成功,如果安装成功,则显示类似如下信息: ``` $ fis3 -v @@ -43,7 +43,7 @@ $ fis3 -v ``` 如果提示找不到 `fis3` 命令并且 **npm** 安装成功退出,请参考文档 [fis#565](https://github.com/fex-team/fis/issues/565) 解决 - +如果windows下提示 `basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")` 则找到 C:\Users\win-7\AppData\Roaming\npm下面的fis脚本删除,留下fis.cmd就好了(没有识别系统是不是Windows) ### 升级 FIS3 ```bash diff --git a/doc/docs/beginning/intro.md b/doc/docs/beginning/intro.md index 79a25084a..f5ef2d7ad 100644 --- a/doc/docs/beginning/intro.md +++ b/doc/docs/beginning/intro.md @@ -2,6 +2,6 @@ ![FIS Logo](https://raw.githubusercontent.com/fex-team/fis3/master/doc/logo.png) -### FIS3 是什么 +### FIS3 是什么? FIS3 是面向前端的工程构建工具。解决前端工程中性能优化、资源加载(异步、同步、按需、预加载、依赖管理、合并、内嵌)、模块化开发、自动化工具、开发规范、代码部署等问题。 diff --git a/doc/docs/beginning/release.md b/doc/docs/beginning/release.md index 57e767cc5..2d2d1d0d1 100644 --- a/doc/docs/beginning/release.md +++ b/doc/docs/beginning/release.md @@ -85,7 +85,7 @@ fis3 release -d ../output ### 配置文件 -默认配置文件为 `fis-conf.js`,FIS3 编译的整个流程都是通过配置来控制的。FIS3 定义了一种类似 CSS 的[配置方式](../api/config.md)。固化了构建流程,以期让工程构建变得简单。 +默认配置文件为 `fis-conf.js`,FIS3 编译的整个流程都是通过配置来控制的。FIS3 定义了一种类似 CSS 的[配置方式](../api/config.md)。固化了构建流程,让工程构建变得简单。 #### fis.match() @@ -94,8 +94,8 @@ fis3 release -d ../output ```js fis.match(selector, props); ``` -- `selector` :FIS3 把匹配文件路径的路径作为selector,匹配到的文件会分配给它设置的 `props` -- `props` :编译规则属性,包括文件属性和插件属性,[更多属性](../api/config-props.md) +- `selector` :FIS3 把匹配文件路径的路径作为selector,匹配到的文件会分配给它设置的 `props`。关于 selector 语法,请参看 [Glob 说明](/fis3/docs/api/config-glob.html) +- `props` :编译规则属性,包括文件属性和插件属性,[更多属性](../api/config-props.md#%E5%9F%BA%E6%9C%AC%E5%B1%9E%E6%80%A7) 我们修改例子的配置文件 `fis-conf.js`,添加以下内容 @@ -258,6 +258,24 @@ fis3 release -d ../output ![](./img/demo-hash-css-diff.png) - 对应 url 也带上了 md5 戳 +### 片段编译 + +有些插件会对文件中的一部分先进行片段编译`fis.compile.partial`, 这时可以对相应的片段编译配置对应的规则。 + +``` +// vue组件中的less片段处理 +fis.match('src/vue/**.vue:less', { + rExt: 'css', + parser: fis.plugin('less'), + release: 'xxx' // 这个无效 +}); + +// 注意:因为组件中的样式片段编译只是编译内容,所以上面的release配置是无效的。要配置其release,需要针对生成的css文件: +fis.match('src/vue/(**.css)', { + release: '/vue-style/$1' +}); +``` + ### 压缩资源 为了减少资源网络传输的大小,通过压缩器对 js、css、图片进行压缩是一直以来前端工程优化的选择。在 FIS3 中这个过程非常简单,通过给文件配置压缩器即可。 @@ -336,7 +354,7 @@ fis.match('*.{js,css,png}', { // 启用 fis-spriter-csssprites 插件 fis.match('::package', { spriter: fis.plugin('csssprites') -}) +}); // 对 CSS 进行图片合并 fis.match('*.css', { diff --git a/doc/docs/build.md b/doc/docs/build.md index a61d08fd5..9c88c672f 100644 --- a/doc/docs/build.md +++ b/doc/docs/build.md @@ -42,7 +42,7 @@ fis.release = function (opt) { } ``` -如上述代码,整个 FIS3 的构建流程大题概括分为三个阶段。 +如上述代码,整个 FIS3 的构建流程大体概括分为三个阶段。 1. 扫描项目目录拿到文件并初始化出一个文件对象列表 2. 对文件对象中每一个文件进行[单文件编译](#单文件编译流程) diff --git a/doc/docs/common-plugin.md b/doc/docs/common-plugin.md new file mode 100644 index 000000000..490e035c6 --- /dev/null +++ b/doc/docs/common-plugin.md @@ -0,0 +1,378 @@ +## 常用插件列表 + + +### parser 插件 + +#### [fis-parser-babel-5.x](https://github.com/fex-team/fis-parser-babel-5.x) + +支持 es6、es7 或者 jsx 编译成 es5 + +```js +fis.match('*.jsx', { + parser: fis.plugin('babel-5.x') +}) +``` + +#### [fis3-parser-typescript](https://github.com/fex-team/fis3-parser-typescript) + +支持 typescript、es6 或者 jsx 编译成 js。速度相比 babel 略快,但是 es7 跟进较慢。 + +```js +fis.match('*.jsx', { + parser: fis.plugin('typescript') +}) +``` + +#### [fis-parser-less-2.x](https://github.com/fouber/fis-parser-less-2.x) + +支持 less 编译成 css + +```js +fis.match('*.less', { + parser: fis.plugin('less-2.x'), + rExt: '.css' +}) +``` + +#### [fis-parser-node-sass](https://github.com/fex-team/fis-parser-node-sass) + +支持 sass/scss 编译成 css。 + +```js +fis.match('*.scss', { + rExt: '.css', + parser: fis.plugin('node-sass', { + // options... + }) +}) +``` + +#### [fis-parser-jdists](https://github.com/fex-team/fis-parser-jdists) + +一款强大的代码块预处理工具。比如加上如下配置,在 `debug` 注释中的代码,在正式环境下自动移除。 + +```js +fis.media('production').match('*.js', { + parser: fis.plugin('jdists', { + remove: "debug" + }) +}) +``` + +```js +/**/ +// 这段代码在 fis3 release production 的时候会被移除。 +console.log(debug); +/**/ +``` + +### preprocessor 插件 + + +#### [fis3-preprocessor-js-require-css](https://github.com/fex-team/fis3-preprocessor-js-require-css) + +允许你在 js 中直接 `require` css 文件。 + +```js +fis.match('*.{js,es,es6,jsx,ts,tsx}', { + preprocessor: fis.plugin('js-require-css') +}) +``` + +#### [fis3-preprocessor-js-require-file](https://github.com/fex-team/fis3-preprocessor-js-require-file) + +允许你在 js 中直接 `require` 文件。比如图片,json, 其他静态文件。 + +require 部分将会替换成部署后的 url。 同时还支持,如果文件小于 20K 直接替换成 base64 字符串。 + +```js +fis.match('*.{js,es,es6,jsx,ts,tsx}', { + preprocessor: fis.plugin('js-require-file') +}) +``` + +### [fis3-preprocessor-autoprefixer](https://www.npmjs.com/package/fis3-preprocessor-autoprefixer) + +自动给 css 属性添加前缀,让标准的 css3 支持更多的浏览器. + +```js +fis.match('*.{css,less,scss}', { + preprocessor: fis.plugin('autoprefixer', { + "browsers": ["Android >= 2.1", "iOS >= 4", "ie >= 8", "firefox >= 15"], + "cascade": true + }) +}) +``` + +### postprocessor 插件 + +待补充 + +### optimizer 插件 + +#### [fis-optimizer-uglify-js](https://github.com/fex-team/fis-optimizer-uglify-js) + +压缩 js 代码。 + +``` +fis.match('*.{js,jsx,ts,tsx,es6,es}', { + optimizer: fis.plugin('uglify-js') +}); +``` + +#### [fis-optimizer-clean-css](https://github.com/fex-team/fis-optimizer-clean-css) + +压缩 css 代码。 + +``` +fis.match('*.{scss,sass,less,css}', { + optimizer: fis.plugin('clean-css',{ + //option + }) +}) +``` + +#### [fis-optimizer-png-compressor](https://github.com/fex-team/fis-optimizer-png-compressor) + +压缩 png 图片。 + +```js +fis.match('*.png', { + optimizer: fis.plugin('png-compressor',{ + //option + }) +}) +``` + +#### [fis-optimizer-smarty-xss](https://github.com/fex-team/fis-optimizer-smarty-xss) + +smarty xss 修复插件。 [fis3-smarty](https://github.com/fex-team/fis3-smarty) 中已默认配置好。 + +``` +fis.match('*.tpl', { + optimizer: fis.plugin('smarty-xss') +}) +``` + + +#### [fis-optimizer-html-compress](https://github.com/pianist829/fis-optimizer-html-compress) + +smarty html 代码压缩插件。 [fis3-smarty](https://github.com/fex-team/fis3-smarty) 中已默认配置好。 + +``` +fis.match('*.tpl', { + optimizer: fis.plugin('html-compress') +}) +``` + +#### [jello-optimizer-velocity-xss](https://github.com/fex-team/jello-optimizer-velocity-xss) + +velocity 模板 xss 修复插件。 + +``` +fis.match('*.vm', { + optimizer: fis.plugin('velocity-xss') +}) +``` + + +### package 插件 + +#### [fis3-packager-map](https://github.com/fex-team/fis3-packager-map) + +在 fis3 中自带了, 默认的打包插件。详情见插件 [Readme](https://github.com/fex-team/fis3-packager-map) + +#### [fis3-packager-deps-pack](https://github.com/fex-team/fis3-packager-deps-pack) + +支持包含依赖的打包插件 + +```js +fis.match('::packager', { + packager: fis.plugin('deps-pack', { + + 'pkg/hello.js': [ + + // 将 main.js 加入队列 + '/static/hello/src/main.js', + + // main.js 的所有同步依赖加入队列 + '/static/hello/src/main.js:deps', + + // 将 main.js 所以异步依赖加入队列 + '/static/hello/src/main.js:asyncs', + + // 移除 comp.js 所有同步依赖 + '!/static/hello/src/comp.js:deps' + ], + + // 也可以从将 js 依赖中 css 命中。 + 'pkg/hello.css': [ + // main.js 的所有同步依赖加入队列 + '/static/hello/src/main.js:deps', + ] + }) +}); +``` + +#### [fis3-postpackager-loader](https://github.com/fex-team/fis3-postpackager-loader) + +静态资源前端加载器,纯前端项目必备插件。自动加载页面中用到的资源,同时还能按页面级别的All In One 打包。 + +``` +fis.match('::packager', { + postpackager: fis.plugin('loader') +}); +``` + + +### deploy 插件 + +#### [fis3-deploy-local-deliver](https://github.com/fex-team/fis3-deploy-local-deliver) + +已自带 fis3 中。用来将文件产出到本地。 + +```js +fis.match('*.js', { + deploy: fis.plugin('local-deliver', { + to: './output' + }) +}) +``` + +#### [fis3-deploy-http-push](https://github.com/fex-team/fis3-deploy-http-push) + +将产出文件通过 http post 到目标机器。 + +```js +fis.match('*.js', { + deploy: fis.plugin('http-push', { + //如果配置了receiver,fis会把文件逐个post到接收端上 + receiver: 'http://www.example.com:8080/receiver.php', + //这个参数会跟随post请求一起发送 + to: '/home/fis/www' + }) +}) +``` + +#### [fis3-deploy-tar](https://github.com/fex-team/fis3-deploy-tar) + +将产出文件,打包成 tar 文件。 + +``` +fis.match('**', { + deploy: [ + fis.plugin('tar'), + + fis.plugin('local-deliver', { + to: './output' + }) + ] +}) +``` + +#### [fis3-deploy-zip](https://github.com/fex-team/fis3-deploy-zip) + +将产出文件,打包成 zip 文件。 + +``` +fis.match('**', { + deploy: [ + fis.plugin('zip'), + + fis.plugin('local-deliver', { + to: './output' + }) + ] +}) +``` + +#### [fis3-deploy-encoding](https://github.com/fex-team/fis3-deploy-encoding) + +将产出的文件做编码处理。 + +``` +fis.match('**', { + charset: 'gbk', + deploy: [ + fis.plugin('encoding'), + fis.plugin('local-deliver') + ] +}); +``` + +#### [fis3-deploy-replace](https://github.com/fex-team/fis3-deploy-replace) + +将产出的文件,做文本替换。 + +``` +fis.match('**', { + deploy: [ + fis.plugin('replace', { + from: /(img|cdn)\.baidu\.com/, + to: function ($0, $1) { + switch ($1) { + case 'img': + return '127.0.0.1:8080'; + case 'cdn': + return '127.0.0.1:8081'; + } + return $0; + } + }), + fis.plugin('local-deliver') + ] +}); +``` + +#### [fis3-deploy-skip-packed](https://github.com/fex-team/fis3-deploy-skip-packed) + +将产出的文件过滤掉已被打包的。 + +``` +fis.match('**', { + deploy: [ + fis.plugin('skip-packed', { + // 配置项 + }), + + fis.plugin('local-deliver', { + to: 'output' + }) + ] +}) +``` + +### hook 插件 + +#### [fis3-hook-commonjs](https://github.com/fex-team/fis3-hook-commonjs) + +[强烈推荐] CommonJs 模块化支持插件。 详情请见 [README](https://github.com/fex-team/fis3-hook-commonjs) + +``` +fis.hook('commonjs') +``` + + +#### [fis3-hook-amd](https://github.com/fex-team/fis3-hook-amd) + +AMD 模块化支持插件。 + +#### [fis3-hook-cmd](https://github.com/fex-team/fis3-hook-cmd) + +CMD 模块化支持插件。 + +#### [fis3-hook-system](https://github.com/fex-team/fis3-hook-system) + +System 模块化支持插件。 + +#### [fis3-hook-node_modules](https://github.com/fex-team/fis3-hook-node_modules) + +支持 npm 组件的插件,npm 包中的模块,直接通过包名就能 `require` 到。 + +``` +fis.hook('node_modules'); +``` + +#### [fis3-hook-relative](https://github.com/fex-team/fis3-hook-relative) + +支持产出为相对路径。 diff --git a/doc/docs/lv2.md b/doc/docs/lv2.md index cfbb27e88..d7369972c 100644 --- a/doc/docs/lv2.md +++ b/doc/docs/lv2.md @@ -46,7 +46,9 @@ my-proj/node_modules/fis3-parser-translate-es6/index.js ```js // vi index.js -// babel node.js api 只需要 babel-core 即可 +// babel node.js api 只有 babel-core 不能完成翻译 +// babel-core 需要安装依赖 babel-preset-es2015 +// 参考: 阮一峰的es6入门 http://es6.ruanyifeng.com/#docs/intro var babel = require('babel-core'); module.exports = function (content, file, options) { var result = babel.transform(content, opts); @@ -69,7 +71,9 @@ my-proj/index.html ```js fis.match('*.es6', { - parser: fis.plugin('translate-es6'), + parser: fis.plugin('translate-es6', { + presets: ['es2015'] + }), rExt: '.js' // .es6 最终修改其后缀为 .js }) ``` diff --git a/doc/docs/lv3.md b/doc/docs/lv3.md index 60f756ffc..a751c9b6e 100644 --- a/doc/docs/lv3.md +++ b/doc/docs/lv3.md @@ -247,8 +247,10 @@ package.json } else { fis = require(env.modulePath); } - fis.set('system.localNPMFolder', path.join(env.cwd, 'node_modules/foo')); - fis.set('system.globalNPMFolder', path.dirname(__dirname)); + // 配置插件查找路径,优先查找本地项目里面的 node_modules + // 然后才是全局环境下面安装的 fis3 目录里面的 node_modules + fis.require.paths.unshift(path.join(env.cwd, 'node_modules')); + fis.require.paths.push(path.join(path.dirname(__dirname), 'node_modules')); fis.cli.run(argv, env); }); ``` diff --git a/doc/docs/node-mock.md b/doc/docs/node-mock.md index 44dada003..4d088e90b 100644 --- a/doc/docs/node-mock.md +++ b/doc/docs/node-mock.md @@ -6,9 +6,9 @@ fis 中默认的 node 服务就支持此功能。 ## 步骤 -1. 准备好假数据文件,如 sample.json 文件,放在服务器的 `/test/sample.json` 目录,确保通过 `http://127.0.0.1:8080/test/sample.json` 可访问到。 +1. 准备好假数据文件,如 sample.json 文件,放在服务器的 `/mock/sample.json` 目录,确保通过 `http://127.0.0.1:8080/mock/sample.json` 可访问到。 - ```json + ```jsonte { "error": 0, "message": "ok", @@ -18,10 +18,10 @@ fis 中默认的 node 服务就支持此功能。 } } ``` -2. 准备一个 `server.conf` 配置文件,放在服务器目录的 `/config/server.conf`,内容如下。 +2. 准备一个 `server.conf` 配置文件,放在服务器目录的 `/mock/server.conf`,内容如下。 ``` - rewrite ^\/api\/user$ /test/sample.json + rewrite ^\/api\/user$ /mock/sample.json ``` 3. 然后当你请求 `http://127.0.0.1:8080/api/user` 的时候,返回的就是 sample.json 中的内容。 @@ -33,7 +33,7 @@ fis 中默认的 node 服务就支持此功能。 指令名称 正则规则 目标文件 ``` -* `指令名称` 支持 `rewrite` 和 `redirect`。 +* `指令名称` 支持 `rewrite` 、 `redirect` 和 `proxy`。 * `正则规则` 用来命中需要作假的请求路径。 * `目标文件` 设置转发的目标地址,需要配置一个可请求的 url 地址。 @@ -42,28 +42,26 @@ fis 中默认的 node 服务就支持此功能。 推荐以下存放规范。 ``` -└── test +└── mock ├── sample.json └── server.conf ``` -然后配置 fis-conf.js, 保证产出到服务端的路径是正确的。 +## 直接代理到其他服务的 api 地址。 -```js -fis.match('/test/**', { - release: '$0' -}); +这个功能要求 fis3 >= 3.3.29 使用格式如: -fis.match('/test/server.conf', { - release: '/config/server.conf' -}); ``` +proxy ^\/api\/test http://127.0.0.1:9119/api/test +``` + +ps: 还在测试中,目前简单的 API 代理没问题,如果 auth 验证什么的可能就会跪,后续会继续优化。 ## 动态假数据 -静态的假数据可以通过 json 文件提供,那么动态数据怎么提供?node 服务器可以通过 js 的方式提供动态家数据。 +静态的假数据可以通过 json 文件提供,那么动态数据怎么提供?node 服务器可以通过 js 的方式提供动态假数据。 -/test/dynamic.js +/mock/dynamic.js ```js module.exports = function(req, res, next) { @@ -80,7 +78,7 @@ module.exports = function(req, res, next) { 然后结合 server.conf 就可以模拟各种动态请求了。 ``` -rewrite ^\/api\/dynamic\/time$ /test/dynamic.js +rewrite ^\/api\/dynamic\/time$ /mock/dynamic.js ``` 如上面的例子,当请求 `http://127.0.0.1:8080/api/dynamic/time` 时,返回:`Hello world The time is 1442556037130` diff --git a/doc/docs/pack.md b/doc/docs/pack.md new file mode 100644 index 000000000..56b475418 --- /dev/null +++ b/doc/docs/pack.md @@ -0,0 +1,130 @@ +## 资源合并(打包) + +关于资源合并,在 fis3 中有多种方式来实现。为了搞清楚他们都有些什么特点,适用于什么场合,我觉得有必要聚集在一起一一说明下。 + + +### packTo + +命中目标文件,设置 packTo 即能完成简单的合并操作。 + +```js +fis.match('/static/folderA/**.js', { + packTo: '/static/pkg/folderA.js' +}); + +fis.match('/static/folderA/**.css', { + packTo: '/static/pkg/folderA.css' +}); +``` + +合并的列表中,被依赖的文件会自动提前。但是并不是所有的资源都严格的指定了依赖,所以有时候需要控制顺序。可以通过配置 `packOrder` 来控制,`packOrder` 越小越在前面。 + +``` +fis.match('/static/folderA/**.js', { + packTo: '/static/pkg/folderA.js' +}); + +fis.match('/static/folderA/file1.js', { + packOrder: -100 +}); +``` + +这种打包方式最简单,但是对于顺序配置有点麻烦,如果 A 必须在 B 的前面,最好的方式是让 B 指定依赖 A。 + +### [fis3-packager-map](https://github.com/fex-team/fis3-packager-map) + +packTo 其实用的就是这个插件,fis3 内部其实就是把 packTo 转成了这个插件的配置。 + +以下配置完全等价于上面 packTo 的配置。 + +```js +fis.match('::package', { + packager: fis.plugin('map', { + '/static/pkg/folderA.js': '/static/folderA/**.js' + }) +}) +``` + +为什么这种变体的配置方式,是因为用这种方式很好控制顺序。此插件会按配置的顺序来打包。 + +```js +fis.match('::package', { + packager: fis.plugin('map', { + '/static/pkg/folderA.js': [ + '/static/folderA/file1.js', + '/static/folderA/file2.js', + '/static/folderA/**.js' + ] + }) +}) +``` + +### [fis3-packager-deps-pack](https://github.com/fex-team/fis3-packager-deps-pack) + +deps-pack 是在 map 的基础上再扩展了用法,可以快速的命中目标文件的依赖,比如: + +``` +fis.match('::package', { + packager: fis.plugin('deps-pack', { + + 'pkg/hello.js': [ + + // 将 main.js 加入队列 + '/static/hello/src/main.js', + + // main.js 的所有同步依赖加入队列 + '/static/hello/src/main.js:deps', + + // 将 main.js 的所有异步依赖加入队列 + '/static/hello/src/main.js:asyncs', + + // 移除 comp.js 的所有同步依赖 + '!/static/hello/src/comp.js:deps' + ], + + // 也可以从将 js 依赖中 css 命中。 + 'pkg/hello.css': [ + // main.js 的所有同步依赖加入队列 + '/static/hello/src/main.js:deps', + ] + + }) +}); +``` + +以上示例中还有中特殊的用法,即 `!` 打头的规则。他可以在现有结果集中做排除处理。 + +这种打包方式最复杂,但是很多情况下,你需要这些规则来做打包细化。 + +### [fis3-postpackager-loader](https://github.com/fex-team/fis3-postpackager-loader) + +其实它并不是专门做打包的,而是做资源加载的插件。只是他能提供另一种更简单的打包方式。 + +他以页面为单位,分析当前页面用到的所有资源,将所有 js 合并成一个 js,所有的 css 合并成一个 css. + +``` +fis.match('::package', { + postpackager: fis.plugin('loader', { + allInOne: true + }) +}); +``` + +非常简单粗暴,但是有两个缺点。 + +1. 因为他是前端编译期分析,对于使用了后端模板的页面资源分析无能为力,所以它只能适用于纯前端项目。 +2. 它的资源合并是以页面为单位,所以存在公共 js/css 被复制成多分打包多个包里面,导致的结果是,页面间切换,公共部分的 js/css 是没有公用缓存的。 + + 但是这个问题还是能结合前面提到的插件解决的。比如: + + ``` + fis.match('/static/folderA/**.js', { + packTo: '/static/pkg/folderA.js' + }); + ``` + + 以上配置和 loader 的 allInOne 同时配置了的话,结果会是这样的, folderA 下面的资源被打包到 folderA.js 中,同时页面里面的**其他资源**走 allInOne 打包。 + + 所以只要勤快点,是可以把公用的资源抽出来的。 + + diff --git a/doc/docs/user-dev/inline.md b/doc/docs/user-dev/inline.md index 328562036..8f4e95eea 100644 --- a/doc/docs/user-dev/inline.md +++ b/doc/docs/user-dev/inline.md @@ -76,6 +76,8 @@

demo.html content

``` + + ### 在js中嵌入资源 在js中,使用编译函数 **__inline()** 来提供内容嵌入能力。可以利用这个函数嵌入图片的base64编码、嵌入其他js或者前端模板文件的编译内容, **这些处理对html中script标签里的内容同样有效**。 diff --git a/doc/docs/user-dev/uri.md b/doc/docs/user-dev/uri.md index 06c668b0f..1b0177f9c 100644 --- a/doc/docs/user-dev/uri.md +++ b/doc/docs/user-dev/uri.md @@ -319,7 +319,6 @@ fis.match('/images/(*.{png,gif})', { ```css .style { background: url('http://github.com/images/body-bg.png'); - background: url('http://github.com/static/pic/body-bg_1b8c3e0.png'); } ``` diff --git a/doc/package.json b/doc/package.json index 3b96e2beb..804e37b32 100644 --- a/doc/package.json +++ b/doc/package.json @@ -16,7 +16,7 @@ "license": "MIT", "dependencies": { "fis3-postpackager-loader": "^1.0.17", - "highlight.js": "^8.6.0", + "highlight.js": ">=9.18.2", "marked": "^0.3.3" } } diff --git a/doc/plugins.html b/doc/plugins.html index 12dcbc3b9..0d688171b 100644 --- a/doc/plugins.html +++ b/doc/plugins.html @@ -18,6 +18,9 @@
+
+ 不知道选哪个?去看看常用插件列表里有没有。 +
diff --git a/lib/cache.js b/lib/cache.js index 20be221e1..cac390fd3 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -15,6 +15,7 @@ var Cache = Object.derive(function(path, dir) { } this.timestamp = fis.util.mtime(file).getTime(); this.deps = {}; + this.mDeps = {}; // 记录那些存在缓存依赖,但是项目中没找到的文件。 this.version = fis.version; var info = fis.util.pathinfo(file); @@ -37,6 +38,7 @@ var Cache = Object.derive(function(path, dir) { version: this.version, timestamp: this.timestamp, deps: this.deps, + mDeps: this.mDeps, info: info }; fis.util.write(this.cacheInfo, JSON.stringify(infos)); @@ -58,16 +60,17 @@ var Cache = Object.derive(function(path, dir) { fis.log.debug('cache info read'); if (infos.version == this.version && infos.timestamp == this.timestamp) { var deps = infos['deps']; - for (var f in deps) { - if (deps.hasOwnProperty(f)) { - var d = fis.util.mtime(f); - if (d == 0 || deps[f] != d.getTime()) { - fis.log.debug('cache is expired'); - return false; - } - } + var allValid = Object.keys(deps).every(function(f) { + var d = fis.util.mtime(f); + return d != 0 && deps[f] == d.getTime() + }); + + if (!allValid) { + fis.log.debug('cache is expired'); + return false; } this.deps = deps; + this.mDeps = infos.mDeps; fis.log.debug('cache is valid'); if (file) { file.info = infos.info; @@ -107,20 +110,35 @@ var Cache = Object.derive(function(path, dir) { return this; }, + /** + * 添加没找到的文件依赖,因为后续可能会添加进来。 + * @param {String} filepath 依赖的文件路径。 + */ + addMissingDeps: function(filepath, raw) { + raw = raw || ''; + this.mDeps[filepath] = raw; + return this; + }, + /** * 合并 cache 中的依赖列表。 - * @param {mixed} cache 此对象中的依赖会被合入到该事例依赖中。 + * @param {mixed} cache 此对象中的依赖会被合入到该实例依赖中。 */ mergeDeps: function(cache) { var deps = {}; + var mDeps; + if (cache instanceof Cache) { deps = cache.deps; + mDeps = cache.mDeps; } else if (typeof cache === 'object') { deps = cache; } else { fis.log.error('unable to merge deps of data[%s]', cache); } + fis.util.map(deps, this.deps, true); + mDeps && fis.util.map(mDeps, this.mDeps, true); } }); diff --git a/lib/cli.js b/lib/cli.js index 55d7e1986..27241146f 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -34,6 +34,20 @@ cli.commander = null; */ cli.info = fis.util.readJSON(path.dirname(__dirname) + '/package.json'); +/** + * 支持命令合集 + * @memberOf fis.cli + * @name options + */ +cli.options = { + '-h, --help': 'print this help message', + '-v, --version': 'print product version and exit', + '-r, --root ': 'specify project root', + '-f, --file ': 'specify the file path of `fis-conf.js`', + '--no-color': 'disable colored output', + '--verbose': 'enable verbose mode' +}; + /** * 显示帮助信息,主要用来格式化信息,处理缩进等。fis command 插件,可以用此方法来输出帮助信息。 * @@ -59,14 +73,7 @@ cli.help = function(cmdName, options, commands) { commands[name] = cmd.desc || ''; }); - options = { - '-h, --help': 'print this help message', - '-v, --version': 'print product version and exit', - '-r, --root ': 'specify project root', - '-f, --file ': 'specify the file path of `fis-conf.js`', - '--no-color': 'disable colored output', - '--verbose': 'enable verbose mode' - }; + options = cli.options; } options = options || {}; @@ -178,11 +185,7 @@ cli.version = function() { * @function */ cli.run = function(argv, env) { - // [node, realPath(bin/fis.js)] - var argvRaw = process.argv; - - process.title = cli.name +' ' + process.argv.slice(2).join(' ') + ' [ ' + env.cwd + ' ]'; - + var cmdName = argv._[0]; if (argv.verbose) { fis.log.level = fis.log.L_ALL; } @@ -191,18 +194,18 @@ cli.run = function(argv, env) { fis.project.setProjectRoot(env.cwd); // 如果指定了 media 值 - if (~['release', 'inspect'].indexOf(argv._[0]) && argv._[1]) { + if (~['release', 'inspect'].indexOf(cmdName) && argv._[1]) { fis.project.currentMedia(argv._[1]); } env.configPath = env.configPath || argv.f || argv.file; - fis.log.throw = argv._[1] !== 'release'; + fis.log.throw = cmdName !== 'release'; if (env.configPath) { try { require(env.configPath); } catch (e) { - if (~['release', 'inspect'].indexOf(argv._[0])) { + if (~['release', 'inspect'].indexOf(cmdName)) { fis.log.error('Load %s error: %s \n %s', env.configPath, e.message, e.stack); } else { fis.log.warn('Load %s error: %s', env.configPath, e.message); @@ -225,24 +228,25 @@ cli.run = function(argv, env) { if (!argv._.length) { cli[argv.v || argv.version ? 'version' : 'help'](); } else { - // tip - // if (argvRaw[2] === 'release' && !env.modulePath) { + // if (cmdName === 'release' && !env.modulePath) { // fis.log.warning('Local `fis3` not found, use global version instead.'); // } - //fix args - var p = argvRaw.indexOf('--no-color'); - ~p && argvRaw.splice(p, 1); - - p = argvRaw.indexOf('--media'); - ~p && argvRaw.splice(p, argvRaw[p + 1][0] === '-' ? 1 : 2); - //register command var commander = cli.commander = require('commander'); - var cmd = fis.require('command', argvRaw[2]); + var cmd = fis.require('command', cmdName); if (cmd.register) { + // [node, realPath(bin/fis.js)] + var argvRaw = process.argv; + //fix args + var p = argvRaw.indexOf('--no-color'); + ~p && argvRaw.splice(p, 1); + + p = argvRaw.indexOf('--media'); + ~p && argvRaw.splice(p, argvRaw[p + 1][0] === '-' ? 1 : 2); + // 兼容旧插件。 cmd.register( commander diff --git a/lib/compile.js b/lib/compile.js index 58fe09773..89a81c8d5 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -4,10 +4,17 @@ var CACHE_DIR; var _ = require('./util.js'); var rType = /\s+type\s*=\s*(['"]?)((?:text|application)\/(.*?))\1/i; var memoryCache = {}; +var compileStack = []; +var path = require('path'); // 待编译完成后,清空内存缓存 fis.on('release:end', function() { memoryCache = {}; + compileStack = []; +}); +fis.on('release:error', function() { + memoryCache = {}; + compileStack = []; }); function revertFromMemory(file, inCache) { @@ -30,7 +37,7 @@ function revertFromMemory(file, inCache) { * @param {String} file 文件对象 * @namespace fis.compile */ -var exports = module.exports = function(file) { +var exports = module.exports = function(file, context) { if (!CACHE_DIR) { fis.log.error('uninitialized compile cache directory.'); } @@ -44,7 +51,9 @@ var exports = module.exports = function(file) { revertFromMemory(file, memoryCache[file.realpath]); return file; } - memoryCache[file.realpath] = file; + + // 只有启用 cache 的时候才存入 memoryCache + file.useCache && (memoryCache[file.realpath] = file); // lint 置前,不使用文件缓存 if (file.isText() && exports.settings.useLint) { @@ -55,6 +64,7 @@ var exports = module.exports = function(file) { fis.log.debug('compile [' + file.realpath + '] start'); fis.emit('compile:start', file); + ~compileStack.indexOf(file.realpath) || compileStack.push(file.realpath); if (file.isFile()) { if (file.useCompile && file.ext && file.ext !== '.') { var cache = file.cache = fis.cache(file.realpath, CACHE_DIR), @@ -72,13 +82,15 @@ var exports = module.exports = function(file) { file.setContent(fis.util.read(file.realpath)); process(file); exports.settings.afterCompile(file); - cache.save(file.getContent(), file.getCacheData()); + fis.log.debug('Save cache [%s] start', file.subpath); + file.useCache && cache.save(file.getContent(), file.getCacheData()); + fis.log.debug('Save cache [%s] end', file.subpath); } } else { file.setContent(file.isText() ? fis.util.read(file.realpath) : fis.util.fs.readFileSync(file.realpath)); } } else if (file.useCompile && file.ext && file.ext !== '.') { - process(file); + process(file, context); } if (file.useHash) { file.getHash(); @@ -86,15 +98,18 @@ var exports = module.exports = function(file) { file.compiled = true; fis.log.debug('compile [' + file.realpath + '] end'); fis.emit('compile:end', file); - file.links.forEach(function(subpath) { + + // 是文件变化触发的重新编译,不进入相关文件编译。 + context && context.fromWatch || file.links.forEach(function(subpath) { var f = fis.file.wrap(fis.project.getProjectPath() + subpath); - if (f.exists() && !lockedCheck(file, f, 'link')) { - lock(file, f, 'link'); - exports(f); - unlock(f, 'link'); + if (f.exists() && !~compileStack.indexOf(f.realpath)) { + compileStack.push(f.realpath); + fis.emit('compile:add', f); } }); + + compileStack.pop(); return file; }; @@ -172,6 +187,8 @@ var map = exports.lang = (function() { var delim = '\u001F'; // Unit Separator var rdelim = '\\u001F'; var slice = [].slice; + var regInvalid = false; + var reg = null; var map = { /** @@ -186,6 +203,7 @@ var map = exports.lang = (function() { } var stack = []; keywords.push(type); + regInvalid = true; map[type] = { wrap: function(value) { return this.ld + slice.call(arguments, 0).join(delim) + this.rd; @@ -218,10 +236,15 @@ var map = exports.lang = (function() { */ Object.defineProperty(map, 'reg', { get: function() { - return new RegExp( - rdelim + '(' + keywords.join('|') + ')(\\d+?)' + rdelim + '([^' + rdelim + ']*?)(?:' + rdelim + '([^' + rdelim + ']+?))?' + rdelim + '\\2\\1' + rdelim, - 'g' - ); + if (regInvalid || !reg) { + reg = new RegExp( + rdelim + '(' + keywords.join('|') + ')(\\d+?)' + rdelim + '([^' + rdelim + ']*?)(?:' + rdelim + '([^' + rdelim + ']*?))?' + rdelim + '\\2\\1' + rdelim, + 'g' + ); + regInvalid = false; + } + + return reg; } }); @@ -239,6 +262,8 @@ var map = exports.lang = (function() { 'hash', // 替换成目标文件的 md5 戳。 'moduleId', // 替换成目标文件的 moduleId 'xlang', // 用来内嵌其他语言 + 'inlineStyle', // 内联样式 + 'sourceMap', 'info' // 能用来包括其他中间码,包裹后可以起到其他中间码的作用,但是不会修改代码源码。 ].forEach(map.add); @@ -275,7 +300,9 @@ function analyseComment(comment, callback) { return prefix + map[type].wrap(value); }; - return comment.replace(reg, callback); + return comment.replace(reg, callback).replace(/(?:@|#)\s+sourceMappingURL=([^\s]+)/g, function(_, value) { + return '# sourceMappingURL=' + map.sourceMap.wrap(value); + }); } /** @@ -292,7 +319,7 @@ function analyseComment(comment, callback) { * @memberOf fis.compile */ function extJs(content, callback, file) { - var reg = /"(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|(\/\/[^\r\n\f]+|\/\*[\s\S]*?(?:\*\/|$))|\b(__inline|__uri|__require|__id|__moduleId|__hash)\s*\(\s*("(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*')\s*\)/g; + var reg = /"(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|((?|>))([\s\S]*?)(?=<\/script\s*>|$)|(|>))([\s\S]*?)(?=<\/style\s*>|$)|<(img|embed|audio|video|link|object|source)\s+[\s\S]*?["'\s\w\/\-](?:>|$)|||$)/ig; - callback = callback || function(m, $1, $2, $3, $4, $5, $6, $7, $8) { + var reg = /(|>))([\s\S]*?)(?=<\/script\s*>|$)|(|>))([\s\S]*?)(?=<\/style\s*>|$)|<(img|embed|audio|video|link|object|source)\s+[\s\S]*?["'\s\w\/\-](?:>|$)||(]+>)||$)|\bstyle\s*=\s*("(?:[^\\"\r\n\f]|\\[\s\S])+"|'(?:[^\\'\n\r\f]|\\[\s\S])+')/ig; + callback = callback || function(m, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) { if ($1) { // diff --git a/test/diff/libs/smarty-3.1.5/plugins/block.textformat.php b/test/diff/libs/smarty-3.1.5/plugins/block.textformat.php deleted file mode 100644 index bdd806731..000000000 --- a/test/diff/libs/smarty-3.1.5/plugins/block.textformat.php +++ /dev/null @@ -1,113 +0,0 @@ - - * Name: textformat
- * Purpose: format text a certain way with preset styles - * or custom wrap/indent settings
- * Params: - *
- * - style         - string (email)
- * - indent        - integer (0)
- * - wrap          - integer (80)
- * - wrap_char     - string ("\n")
- * - indent_char   - string (" ")
- * - wrap_boundary - boolean (true)
- * 
- * - * @link http://www.smarty.net/manual/en/language.function.textformat.php {textformat} - * (Smarty online manual) - * @param array $params parameters - * @param string $content contents of the block - * @param Smarty_Internal_Template $template template object - * @param boolean &$repeat repeat flag - * @return string content re-formatted - * @author Monte Ohrt - */ -function smarty_block_textformat($params, $content, $template, &$repeat) -{ - if (is_null($content)) { - return; - } - - $style = null; - $indent = 0; - $indent_first = 0; - $indent_char = ' '; - $wrap = 80; - $wrap_char = "\n"; - $wrap_cut = false; - $assign = null; - - foreach ($params as $_key => $_val) { - switch ($_key) { - case 'style': - case 'indent_char': - case 'wrap_char': - case 'assign': - $$_key = (string)$_val; - break; - - case 'indent': - case 'indent_first': - case 'wrap': - $$_key = (int)$_val; - break; - - case 'wrap_cut': - $$_key = (bool)$_val; - break; - - default: - trigger_error("textformat: unknown attribute '$_key'"); - } - } - - if ($style == 'email') { - $wrap = 72; - } - // split into paragraphs - $_paragraphs = preg_split('![\r\n]{2}!', $content); - $_output = ''; - - - foreach ($_paragraphs as &$_paragraph) { - if (!$_paragraph) { - continue; - } - // convert mult. spaces & special chars to single space - $_paragraph = preg_replace(array('!\s+!u', '!(^\s+)|(\s+$)!u'), array(' ', ''), $_paragraph); - // indent first line - if ($indent_first > 0) { - $_paragraph = str_repeat($indent_char, $indent_first) . $_paragraph; - } - // wordwrap sentences - if (SMARTY_MBSTRING /* ^phpunit */&&empty($_SERVER['SMARTY_PHPUNIT_DISABLE_MBSTRING'])/* phpunit$ */) { - require_once(SMARTY_PLUGINS_DIR . 'shared.mb_wordwrap.php'); - $_paragraph = smarty_mb_wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut); - } else { - $_paragraph = wordwrap($_paragraph, $wrap - $indent, $wrap_char, $wrap_cut); - } - // indent lines - if ($indent > 0) { - $_paragraph = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraph); - } - } - $_output = implode($wrap_char . $wrap_char, $_paragraphs); - - if ($assign) { - $template->assign($assign, $_output); - } else { - return $_output; - } -} - -?> \ No newline at end of file diff --git a/test/diff/libs/smarty-3.1.5/plugins/function.counter.php b/test/diff/libs/smarty-3.1.5/plugins/function.counter.php deleted file mode 100644 index 3906badf0..000000000 --- a/test/diff/libs/smarty-3.1.5/plugins/function.counter.php +++ /dev/null @@ -1,78 +0,0 @@ - - * Name: counter
- * Purpose: print out a counter value - * - * @author Monte Ohrt - * @link http://www.smarty.net/manual/en/language.function.counter.php {counter} - * (Smarty online manual) - * @param array $params parameters - * @param Smarty_Internal_Template $template template object - * @return string|null - */ -function smarty_function_counter($params, $template) -{ - static $counters = array(); - - $name = (isset($params['name'])) ? $params['name'] : 'default'; - if (!isset($counters[$name])) { - $counters[$name] = array( - 'start'=>1, - 'skip'=>1, - 'direction'=>'up', - 'count'=>1 - ); - } - $counter =& $counters[$name]; - - if (isset($params['start'])) { - $counter['start'] = $counter['count'] = (int)$params['start']; - } - - if (!empty($params['assign'])) { - $counter['assign'] = $params['assign']; - } - - if (isset($counter['assign'])) { - $template->assign($counter['assign'], $counter['count']); - } - - if (isset($params['print'])) { - $print = (bool)$params['print']; - } else { - $print = empty($counter['assign']); - } - - if ($print) { - $retval = $counter['count']; - } else { - $retval = null; - } - - if (isset($params['skip'])) { - $counter['skip'] = $params['skip']; - } - - if (isset($params['direction'])) { - $counter['direction'] = $params['direction']; - } - - if ($counter['direction'] == "down") - $counter['count'] -= $counter['skip']; - else - $counter['count'] += $counter['skip']; - - return $retval; - -} - -?> \ No newline at end of file diff --git a/test/diff/libs/smarty-3.1.5/plugins/function.cycle.php b/test/diff/libs/smarty-3.1.5/plugins/function.cycle.php deleted file mode 100644 index 1778ffb53..000000000 --- a/test/diff/libs/smarty-3.1.5/plugins/function.cycle.php +++ /dev/null @@ -1,106 +0,0 @@ - - * Name: cycle
- * Date: May 3, 2002
- * Purpose: cycle through given values
- * Params: - *
- * - name      - name of cycle (optional)
- * - values    - comma separated list of values to cycle, or an array of values to cycle
- *               (this can be left out for subsequent calls)
- * - reset     - boolean - resets given var to true
- * - print     - boolean - print var or not. default is true
- * - advance   - boolean - whether or not to advance the cycle
- * - delimiter - the value delimiter, default is ","
- * - assign    - boolean, assigns to template var instead of printed.
- * 
- * Examples:
- *
- * {cycle values="#eeeeee,#d0d0d0d"}
- * {cycle name=row values="one,two,three" reset=true}
- * {cycle name=row}
- * 
- * - * @link http://www.smarty.net/manual/en/language.function.cycle.php {cycle} - * (Smarty online manual) - * @author Monte Ohrt - * @author credit to Mark Priatel - * @author credit to Gerard - * @author credit to Jason Sweat - * @version 1.3 - * @param array $params parameters - * @param Smarty_Internal_Template $template template object - * @return string|null - */ - -function smarty_function_cycle($params, $template) -{ - static $cycle_vars; - - $name = (empty($params['name'])) ? 'default' : $params['name']; - $print = (isset($params['print'])) ? (bool)$params['print'] : true; - $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; - $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; - - if (!isset($params['values'])) { - if(!isset($cycle_vars[$name]['values'])) { - trigger_error("cycle: missing 'values' parameter"); - return; - } - } else { - if(isset($cycle_vars[$name]['values']) - && $cycle_vars[$name]['values'] != $params['values'] ) { - $cycle_vars[$name]['index'] = 0; - } - $cycle_vars[$name]['values'] = $params['values']; - } - - if (isset($params['delimiter'])) { - $cycle_vars[$name]['delimiter'] = $params['delimiter']; - } elseif (!isset($cycle_vars[$name]['delimiter'])) { - $cycle_vars[$name]['delimiter'] = ','; - } - - if(is_array($cycle_vars[$name]['values'])) { - $cycle_array = $cycle_vars[$name]['values']; - } else { - $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); - } - - if(!isset($cycle_vars[$name]['index']) || $reset ) { - $cycle_vars[$name]['index'] = 0; - } - - if (isset($params['assign'])) { - $print = false; - $template->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); - } - - if($print) { - $retval = $cycle_array[$cycle_vars[$name]['index']]; - } else { - $retval = null; - } - - if($advance) { - if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { - $cycle_vars[$name]['index'] = 0; - } else { - $cycle_vars[$name]['index']++; - } - } - - return $retval; -} - -?> \ No newline at end of file diff --git a/test/diff/libs/smarty-3.1.5/plugins/function.fetch.php b/test/diff/libs/smarty-3.1.5/plugins/function.fetch.php deleted file mode 100644 index cde98d2ec..000000000 --- a/test/diff/libs/smarty-3.1.5/plugins/function.fetch.php +++ /dev/null @@ -1,216 +0,0 @@ - - * Name: fetch
- * Purpose: fetch file, web or ftp data and display results - * - * @link http://www.smarty.net/manual/en/language.function.fetch.php {fetch} - * (Smarty online manual) - * @author Monte Ohrt - * @param array $params parameters - * @param Smarty_Internal_Template $template template object - * @return string|null if the assign parameter is passed, Smarty assigns the result to a template variable - */ -function smarty_function_fetch($params, $template) -{ - if (empty($params['file'])) { - trigger_error("[plugin] fetch parameter 'file' cannot be empty",E_USER_NOTICE); - return; - } - - $content = ''; - if (isset($template->smarty->security_policy) && !preg_match('!^(http|ftp)://!i', $params['file'])) { - if(!$template->smarty->security_policy->isTrustedResourceDir($params['file'])) { - return; - } - - // fetch the file - if($fp = @fopen($params['file'],'r')) { - while(!feof($fp)) { - $content .= fgets ($fp,4096); - } - fclose($fp); - } else { - trigger_error('[plugin] fetch cannot read file \'' . $params['file'] . '\'',E_USER_NOTICE); - return; - } - } else { - // not a local file - if(preg_match('!^http://!i',$params['file'])) { - // http fetch - if($uri_parts = parse_url(http://github.com/$params['file'])) { - // set defaults - $host = $server_name = $uri_parts['host']; - $timeout = 30; - $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; - $agent = "Smarty Template Engine ". Smarty::SMARTY_VERSION; - $referer = ""; - $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; - $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; - $_is_proxy = false; - if(empty($uri_parts['port'])) { - $port = 80; - } else { - $port = $uri_parts['port']; - } - if(!empty($uri_parts['user'])) { - $user = $uri_parts['user']; - } - if(!empty($uri_parts['pass'])) { - $pass = $uri_parts['pass']; - } - // loop through parameters, setup headers - foreach($params as $param_key => $param_value) { - switch($param_key) { - case "file": - case "assign": - case "assign_headers": - break; - case "user": - if(!empty($param_value)) { - $user = $param_value; - } - break; - case "pass": - if(!empty($param_value)) { - $pass = $param_value; - } - break; - case "accept": - if(!empty($param_value)) { - $accept = $param_value; - } - break; - case "header": - if(!empty($param_value)) { - if(!preg_match('![\w\d-]+: .+!',$param_value)) { - trigger_error("[plugin] invalid header format '".$param_value."'",E_USER_NOTICE); - return; - } else { - $extra_headers[] = $param_value; - } - } - break; - case "proxy_host": - if(!empty($param_value)) { - $proxy_host = $param_value; - } - break; - case "proxy_port": - if(!preg_match('!\D!', $param_value)) { - $proxy_port = (int) $param_value; - } else { - trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); - return; - } - break; - case "agent": - if(!empty($param_value)) { - $agent = $param_value; - } - break; - case "referer": - if(!empty($param_value)) { - $referer = $param_value; - } - break; - case "timeout": - if(!preg_match('!\D!', $param_value)) { - $timeout = (int) $param_value; - } else { - trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); - return; - } - break; - default: - trigger_error("[plugin] unrecognized attribute '".$param_key."'",E_USER_NOTICE); - return; - } - } - if(!empty($proxy_host) && !empty($proxy_port)) { - $_is_proxy = true; - $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); - } else { - $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); - } - - if(!$fp) { - trigger_error("[plugin] unable to fetch: $errstr ($errno)",E_USER_NOTICE); - return; - } else { - if($_is_proxy) { - fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); - } else { - fputs($fp, "GET $uri HTTP/1.0\r\n"); - } - if(!empty($host)) { - fputs($fp, "Host: $host\r\n"); - } - if(!empty($accept)) { - fputs($fp, "Accept: $accept\r\n"); - } - if(!empty($agent)) { - fputs($fp, "User-Agent: $agent\r\n"); - } - if(!empty($referer)) { - fputs($fp, "Referer: $referer\r\n"); - } - if(isset($extra_headers) && is_array($extra_headers)) { - foreach($extra_headers as $curr_header) { - fputs($fp, $curr_header."\r\n"); - } - } - if(!empty($user) && !empty($pass)) { - fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); - } - - fputs($fp, "\r\n"); - while(!feof($fp)) { - $content .= fgets($fp,4096); - } - fclose($fp); - $csplit = preg_split("!\r\n\r\n!",$content,2); - - $content = $csplit[1]; - - if(!empty($params['assign_headers'])) { - $template->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0])); - } - } - } else { - trigger_error("[plugin fetch] unable to parse URL, check syntax",E_USER_NOTICE); - return; - } - } else { - // ftp fetch - if($fp = @fopen($params['file'],'r')) { - while(!feof($fp)) { - $content .= fgets ($fp,4096); - } - fclose($fp); - } else { - trigger_error('[plugin] fetch cannot read file \'' . $params['file'] .'\'',E_USER_NOTICE); - return; - } - } - - } - - - if (!empty($params['assign'])) { - $template->assign($params['assign'],$content); - } else { - return $content; - } -} - -?> \ No newline at end of file diff --git a/test/diff/libs/smarty-3.1.5/plugins/function.html_checkboxes.php b/test/diff/libs/smarty-3.1.5/plugins/function.html_checkboxes.php deleted file mode 100644 index 1e8beb486..000000000 --- a/test/diff/libs/smarty-3.1.5/plugins/function.html_checkboxes.php +++ /dev/null @@ -1,211 +0,0 @@ - - * Type: function
- * Name: html_checkboxes
- * Date: 24.Feb.2003
- * Purpose: Prints out a list of checkbox input types
- * Examples: - *
- * {html_checkboxes values=$ids output=$names}
- * {html_checkboxes values=$ids name='box' separator='
' output=$names} - * {html_checkboxes values=$ids checked=$checked separator='
' output=$names} - *
- * Params: - *
- * - name       (optional) - string default "checkbox"
- * - values     (required) - array
- * - options    (optional) - associative array
- * - checked    (optional) - array default not set
- * - separator  (optional) - ie 
or   - * - output (optional) - the output next to each checkbox - * - assign (optional) - assign the output as an array to this variable - *
- * - * @link http://www.smarty.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} - * (Smarty online manual) - * @author Christopher Kvarme - * @author credits to Monte Ohrt - * @version 1.0 - * @param array $params parameters - * @param object $template template object - * @return string - * @uses smarty_function_escape_special_chars() - */ -function smarty_function_html_checkboxes($params, $template) -{ - require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'); - - $name = 'checkbox'; - $values = null; - $options = null; - $selected = array(); - $separator = ''; - $labels = true; - $label_ids = false; - $output = null; - - $extra = ''; - - foreach($params as $_key => $_val) { - switch($_key) { - case 'name': - case 'separator': - $$_key = (string) $_val; - break; - - case 'labels': - case 'label_ids': - $$_key = (bool) $_val; - break; - - case 'options': - $$_key = (array) $_val; - break; - - case 'values': - case 'output': - $$_key = array_values((array) $_val); - break; - - case 'checked': - case 'selected': - if (is_array($_val)) { - $selected = array(); - foreach ($_val as $_sel) { - if (is_object($_sel)) { - if (method_exists($_sel, "__toString")) { - $_sel = smarty_function_escape_special_chars((string) $_sel->__toString()); - } else { - trigger_error("html_checkboxes: selected attribute contains an object of class '". get_class($_sel) ."' without __toString() method", E_USER_NOTICE); - continue; - } - } else { - $_sel = smarty_function_escape_special_chars((string) $_sel); - } - $selected[$_sel] = true; - } - } elseif (is_object($_val)) { - if (method_exists($_val, "__toString")) { - $selected = smarty_function_escape_special_chars((string) $_val->__toString()); - } else { - trigger_error("html_checkboxes: selected attribute is an object of class '". get_class($_val) ."' without __toString() method", E_USER_NOTICE); - } - } else { - $selected = smarty_function_escape_special_chars((string) $_val); - } - break; - - case 'checkboxes': - trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); - $options = (array) $_val; - break; - - case 'assign': - break; - - default: - if(!is_array($_val)) { - $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; - } else { - trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); - } - break; - } - } - - if (!isset($options) && !isset($values)) - return ''; /* raise error here? */ - - $_html_result = array(); - - if (isset($options)) { - foreach ($options as $_key=>$_val) { - $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids); - } - } else { - foreach ($values as $_i=>$_key) { - $_val = isset($output[$_i]) ? $output[$_i] : ''; - $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids); - } - } - - if(!empty($params['assign'])) { - $template->assign($params['assign'], $_html_result); - } else { - return implode("\n", $_html_result); - } - -} - -function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids) { - $_output = ''; - - if (is_object($value)) { - if (method_exists($value, "__toString")) { - $value = (string) $value->__toString(); - } else { - trigger_error("html_options: value is an object of class '". get_class($value) ."' without __toString() method", E_USER_NOTICE); - return ''; - } - } else { - $value = (string) $value; - } - - if (is_object($output)) { - if (method_exists($output, "__toString")) { - $output = (string) $output->__toString(); - } else { - trigger_error("html_options: output is an object of class '". get_class($output) ."' without __toString() method", E_USER_NOTICE); - return ''; - } - } else { - $output = (string) $output; - } - - if ($labels) { - if ($label_ids) { - $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!u', '_', $name . '_' . $value)); - $_output .= '