├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── README.md ├── app ├── app.js ├── app.json ├── app.scss ├── components │ ├── one-component │ │ ├── one-component.js │ │ ├── one-component.json │ │ ├── one-component.scss │ │ └── one-component.wxml │ ├── three-component │ │ ├── three-component.js │ │ ├── three-component.json │ │ ├── three-component.scss │ │ └── three-component.wxml │ └── two-component │ │ ├── two-component.js │ │ ├── two-component.json │ │ ├── two-component.scss │ │ └── two-component.wxml ├── coverage │ ├── clover.xml │ ├── coverage-final.json │ ├── lcov-report │ │ ├── block-navigation.js │ │ ├── favicon.png │ │ ├── index.html │ │ ├── prettify.js │ │ ├── sort-arrow-sprite.png │ │ ├── sorter.js │ │ └── util.js.html │ └── lcov.info ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.scss │ │ └── index.wxml │ └── one │ │ ├── one.js │ │ ├── one.json │ │ ├── one.scss │ │ └── one.wxml ├── project.config.json ├── sitemap.json ├── tests │ └── index.test.js └── utils │ └── util.js ├── babel.config.js ├── cli ├── index.js └── template │ ├── components │ ├── components.js │ ├── components.json │ ├── components.scss │ └── components.wxml │ └── pages │ ├── pages.js │ ├── pages.json │ ├── pages.scss │ └── pages.wxml ├── img └── github.png ├── jest.config.js ├── package-lock.json ├── package.json ├── webpack.compress.js ├── webpack.config.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | !.eslintrc.js 2 | !.prettierrc.js 3 | !package.json 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true 5 | }, 6 | extends: 'eslint:recommended', 7 | parser: 'babel-eslint', 8 | parserOptions: { 9 | ecmaVersion: 6, 10 | sourceType: 'module' 11 | }, 12 | rules: { 13 | 'no-undef': 0, 14 | 'no-unused-vars': 0 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.map 2 | .DS_Store 3 | .vscode/ 4 | .idea/ 5 | *.css 6 | *.wxss 7 | node_modules 8 | /app/assets/img 9 | /app/analyzer -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | eslintIntegration: true, 3 | // 一行最多 100 字符 4 | printWidth: 100, 5 | // 使用 4 个空格缩进 6 | tabWidth: 4, 7 | // 不使用缩进符,而使用空格 8 | useTabs: true, 9 | // 行尾需要有分号 10 | semi: true, 11 | // 使用单引号 12 | singleQuote: true, 13 | // 对象的 key 仅在必要时用引号 14 | quoteProps: 'as-needed', 15 | // jsx 不使用单引号,而使用双引号 16 | jsxSingleQuote: false, 17 | // 末尾不需要逗号 18 | trailingComma: 'none', 19 | // 大括号内的首尾需要空格 20 | bracketSpacing: true, 21 | // jsx 标签的反尖括号需要换行 22 | jsxBracketSameLine: false, 23 | // 箭头函数,只有一个参数的时候,也需要括号 24 | arrowParens: 'always', 25 | // 每个文件格式化的范围是文件的全部内容 26 | rangeStart: 0, 27 | rangeEnd: Infinity, 28 | // 不需要写文件开头的 @prettier 29 | requirePragma: false, 30 | // 不需要自动在文件开头插入 @prettier 31 | insertPragma: false, 32 | // 使用默认的折行标准 33 | proseWrap: 'preserve', 34 | // 根据显示样式决定 html 要不要折行 35 | htmlWhitespaceSensitivity: 'css', 36 | // 换行符使用 lf 37 | endOfLine: 'lf' 38 | }; 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 小程序开发现状: 2 | 3 | 1. 开发工具不好使用(无法热更新,编译缓慢); 4 | 2. 无法使用css预处理语言(Sass、Less),有些IDE的插件可以监听编译,但不同编辑器需要额外安装; 5 | 3. 无法使用工程化(图片自动压缩,文件监听编译等); 6 | 4.编码繁琐(创建一个页面,需要新建4个文件(.wxml、.js、.json、.wxss),每次新建都需要新建4次或者复制文件比较浪费时间); 7 | 5.团队多人协作,代码风格、使用的编辑器不一致; 8 | 9 | ## 技术选型: 10 | 11 | 在进行小程序项目启动,进行技术选型的时候,对市场上多个小程序框架进行了考虑: 12 | 13 | uni-app、mpVue、wepy、taro、 kbone 14 | 15 | 团队成员mpvue、wepy、uni-app都有实际的项目经验,且根据Github上的star数还有issue,最后决定回到到使用原生开发。 16 | 17 | ### 原因: 18 | 虽然框架有些很成熟,有工程化和跨端的解决方案,也有实际的上线项目,但考虑到后续一些支撑性的问题(维护,文档,坑等),在github上看了issue,有些已经没在维护了。 19 | 20 | 想着让项目持续迭代,不受第三方框架限制,保持稳健,最后决定使用原生,跟着官方的迭代升级,自己维护,引入前端工程化的思想,提高繁琐的流程以及开发效率。 21 | 22 | ## 引入工程化 23 | 24 | 基于Webpack4.x,自定义Webpack配置 25 | 26 | 1. scss编译为wxss:定义全局变量,使用公共的样式文件,提高css开发效率和可维护性; 27 | 28 | 2. 自动压缩图片资源 : 小程序对包大小有限制,压缩图片大小可以减少空间,加快页面加载;普通的图片压缩需要将图片上传到在线图片压缩网站,压缩完再保存下来,效率比较低。现在执行命令就可以自动压缩图片。 29 | 30 | ## 代码规范 31 | 32 | 1. eslint: 能在js运行前就识别一些基础的语法错误,减少不必要的小问题,提高调试效率; 33 | 34 | 2. husky、line-staged、prettier: 统一团队代码规范: 当执行代码提交到git仓库时,会将已改动文件的代码格式化统一规范的代码风格; 35 | 36 | 37 | ## 命令行创建页面和组件模板 38 | 39 | 1. 小程序每次新建页面或者组件,需要依赖4个文件(.wxml,.js,.wxss,.json)。只需要执行npm run create命令,会提示选择创建页面还是组件,选择完成输入页面或者组件的名字,会自动生成4个模板文件(.wxml,.js,json,.scss)到对应的目录 40 | 41 | ## 引入jest单元测试 42 | 43 | 1. 生成测试覆盖率 44 | 45 | ## 项目结构 46 | 47 | app -> 小程序程序的入口,使用微信开发者工具制定app目录 48 | cli -> 生pages和components的模板脚手架 49 | img -> 图片资源原文件 50 | .eslintignore 51 | .eslintrc.js 52 | .gitignore(忽略wxss的提交,多人和做改动,容易有冲突,将scss文件传到服务器就好了) 53 | .prettierrc.js(代码格式化风格配置) 54 | babel.config.js 55 | jest.config.js(单元测试配置文件) 56 | webpack.compress.js(指定入口图片资源文件,将图片压缩编译到小程序的资源目录) 57 | webpack.config.js -> (工程化入口文件,指定入口scss文件,监听文件变化,自动将scss编译为wxss) 58 | 项目使用的包文件 59 | webpack、babel、eslint: 转换、规范js 60 | chalk: console.log打印彩色颜色 61 | scss、css-loader: 编译scss 62 | figlet: 控制台显示字体样式 63 | husky,line-staged,prettier: 代码格式化相关 64 | jest、miniprogram-simulate: 单元测试 65 | 66 | ## 项目运行 67 | 68 | . 安装依赖 69 | 70 | npm install 或 yarn install 71 | 72 | . 编译scss 73 | 74 | npm run dev 75 | 76 | . 压缩图片 77 | 78 | npm run img 79 | 80 | . 单元测试 81 | 82 | npm run test(生成测试报告) 83 | npm run test:watch(监听测试文件改动--开发环境下使用) 84 | 85 | 86 | 87 | ## 其他思考 88 | 89 | 工程化的初衷就是为了减少重复性的操作,提高编码的效率和乐趣。 90 | 91 | JavaScript是弱类型语言,好处是灵活,坏处是太灵活(多人协作,维护别人写的代码就是很痛苦了)。 92 | 93 | 项目最主要的是稳健,可高度自定义拓展,不拘束于版本和地上那方,特别多人协作的团队,工程化能给团队带来更多的收益,后续也会考虑将TypeScript、Docker等其他好的方案引入项目。 94 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || []; 6 | logs.unshift(Date.now()); 7 | wx.setStorageSync('logs', logs); 8 | 9 | // 登录 10 | wx.login({ 11 | success: (res) => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }); 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: (res) => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: (res) => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo; 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res); 29 | } 30 | } 31 | }); 32 | } 33 | } 34 | }); 35 | }, 36 | globalData: { 37 | userInfo: null 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /app/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages":[ 3 | "pages/index/index" 4 | ], 5 | "window":{ 6 | "backgroundTextStyle":"light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTitleText": "Weixin", 9 | "navigationBarTextStyle":"black" 10 | }, 11 | "style": "v2", 12 | "sitemapLocation": "sitemap.json" 13 | } 14 | -------------------------------------------------------------------------------- /app/app.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | height: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | justify-content: space-between; 7 | padding: 200rpx 0; 8 | box-sizing: border-box; 9 | } 10 | .one{ 11 | color:red; 12 | .two{ 13 | color:blue; 14 | } 15 | } -------------------------------------------------------------------------------- /app/components/one-component/one-component.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | // 组件的属性列表 3 | properties: {}, 4 | 5 | // 组件的初始数据 6 | data: {}, 7 | 8 | // 组件的生命周期 9 | lifetimes: { 10 | // 在组件实例刚刚被创建时执行 11 | created() {}, 12 | // 在组件实例进入页面节点树时执行 13 | attached() {}, 14 | // 在组件在视图层布局完成后执行 15 | ready() {}, 16 | // 在组件实例被从页面节点树移除时执行 17 | detached() {} 18 | }, 19 | 20 | // 组件的方法列表 21 | methods: {} 22 | }); 23 | -------------------------------------------------------------------------------- /app/components/one-component/one-component.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /app/components/one-component/one-component.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | 3 | } -------------------------------------------------------------------------------- /app/components/one-component/one-component.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/components/three-component/three-component.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | // 组件的属性列表 3 | properties: {}, 4 | 5 | // 组件的初始数据 6 | data: {}, 7 | 8 | // 组件的生命周期 9 | lifetimes: { 10 | // 在组件实例刚刚被创建时执行 11 | created() {}, 12 | // 在组件实例进入页面节点树时执行 13 | attached() {}, 14 | // 在组件在视图层布局完成后执行 15 | ready() {}, 16 | // 在组件实例被从页面节点树移除时执行 17 | detached() {} 18 | }, 19 | 20 | // 组件的方法列表 21 | methods: {} 22 | }); 23 | -------------------------------------------------------------------------------- /app/components/three-component/three-component.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /app/components/three-component/three-component.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | 3 | } -------------------------------------------------------------------------------- /app/components/three-component/three-component.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/components/two-component/two-component.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | // 组件的属性列表 3 | properties: {}, 4 | 5 | // 组件的初始数据 6 | data: {}, 7 | 8 | // 组件的生命周期 9 | lifetimes: { 10 | // 在组件实例刚刚被创建时执行 11 | created() {}, 12 | // 在组件实例进入页面节点树时执行 13 | attached() {}, 14 | // 在组件在视图层布局完成后执行 15 | ready() {}, 16 | // 在组件实例被从页面节点树移除时执行 17 | detached() {} 18 | }, 19 | 20 | // 组件的方法列表 21 | methods: {} 22 | }); 23 | -------------------------------------------------------------------------------- /app/components/two-component/two-component.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /app/components/two-component/two-component.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | 3 | } -------------------------------------------------------------------------------- /app/components/two-component/two-component.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/coverage/clover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/coverage/coverage-final.json: -------------------------------------------------------------------------------- 1 | {"/Users/mac/Documents/github/miniprogram-cli/app/utils/util.js": {"path":"/Users/mac/Documents/github/miniprogram-cli/app/utils/util.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":3,"column":1}},"1":{"start":{"line":2,"column":1},"end":{"line":2,"column":19}},"2":{"start":{"line":4,"column":0},"end":{"line":6,"column":2}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":1,"column":12},"end":{"line":1,"column":13}},"loc":{"start":{"line":1,"column":27},"end":{"line":3,"column":1}},"line":1}},"branchMap":{},"s":{"0":1,"1":2,"2":1},"f":{"0":2},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"81008584390709ec51a22f155f55044ed3f431f2"} 2 | } 3 | -------------------------------------------------------------------------------- /app/coverage/lcov-report/block-navigation.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var jumpToCode = (function init() { 3 | // Classes of code we would like to highlight in the file view 4 | var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 | 6 | // Elements to highlight in the file listing view 7 | var fileListingElements = ['td.pct.low']; 8 | 9 | // We don't want to select elements that are direct descendants of another match 10 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 | 12 | // Selecter that finds elements on the page to which we can jump 13 | var selector = 14 | fileListingElements.join(', ') + 15 | ', ' + 16 | notSelector + 17 | missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 | 19 | // The NodeList of matching elements 20 | var missingCoverageElements = document.querySelectorAll(selector); 21 | 22 | var currentIndex; 23 | 24 | function toggleClass(index) { 25 | missingCoverageElements.item(currentIndex).classList.remove('highlighted'); 26 | missingCoverageElements.item(index).classList.add('highlighted'); 27 | } 28 | 29 | function makeCurrent(index) { 30 | toggleClass(index); 31 | currentIndex = index; 32 | missingCoverageElements.item(index).scrollIntoView({ 33 | behavior: 'smooth', 34 | block: 'center', 35 | inline: 'center' 36 | }); 37 | } 38 | 39 | function goToPrevious() { 40 | var nextIndex = 0; 41 | if (typeof currentIndex !== 'number' || currentIndex === 0) { 42 | nextIndex = missingCoverageElements.length - 1; 43 | } else if (missingCoverageElements.length > 1) { 44 | nextIndex = currentIndex - 1; 45 | } 46 | 47 | makeCurrent(nextIndex); 48 | } 49 | 50 | function goToNext() { 51 | var nextIndex = 0; 52 | 53 | if (typeof currentIndex === 'number' && currentIndex < missingCoverageElements.length - 1) { 54 | nextIndex = currentIndex + 1; 55 | } 56 | 57 | makeCurrent(nextIndex); 58 | } 59 | 60 | return function jump(event) { 61 | switch (event.which) { 62 | case 78: // n 63 | case 74: // j 64 | goToNext(); 65 | break; 66 | case 66: // b 67 | case 75: // k 68 | case 80: // p 69 | goToPrevious(); 70 | break; 71 | } 72 | }; 73 | })(); 74 | window.addEventListener('keydown', jumpToCode); 75 | -------------------------------------------------------------------------------- /app/coverage/lcov-report/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czero1995/miniprogram-cli/e8fe5a7e82f87f0f21f87cb08b91b25833ad43a7/app/coverage/lcov-report/favicon.png -------------------------------------------------------------------------------- /app/coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for All files 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 3/3 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 1/1 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 3/3 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
FileStatementsBranchesFunctionsLines
util.js 78 |
79 |
100%3/3100%0/0100%1/1100%3/3
92 |
93 |
94 |
95 | 100 | 101 | 102 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /app/coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | window.PR_SHOULD_USE_CONTINUATION = true; 3 | (function () { 4 | var h = ['break,continue,do,else,for,if,return,while']; 5 | var u = [ 6 | h, 7 | 'auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile' 8 | ]; 9 | var p = [ 10 | u, 11 | 'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof' 12 | ]; 13 | var l = [ 14 | p, 15 | 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where' 16 | ]; 17 | var x = [ 18 | p, 19 | 'abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient' 20 | ]; 21 | var R = [ 22 | x, 23 | 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var' 24 | ]; 25 | var r = 26 | 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes'; 27 | var w = [p, 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN']; 28 | var s = 29 | 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END'; 30 | var I = [ 31 | h, 32 | 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None' 33 | ]; 34 | var f = [ 35 | h, 36 | 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END' 37 | ]; 38 | var H = [h, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until']; 39 | var A = [l, R, w, s + I, f, H]; 40 | var e = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/; 41 | var C = 'str'; 42 | var z = 'kwd'; 43 | var j = 'com'; 44 | var O = 'typ'; 45 | var G = 'lit'; 46 | var L = 'pun'; 47 | var F = 'pln'; 48 | var m = 'tag'; 49 | var E = 'dec'; 50 | var J = 'src'; 51 | var P = 'atn'; 52 | var n = 'atv'; 53 | var N = 'nocode'; 54 | var M = 55 | '(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*'; 56 | function k(Z) { 57 | var ad = 0; 58 | var S = false; 59 | var ac = false; 60 | for (var V = 0, U = Z.length; V < U; ++V) { 61 | var ae = Z[V]; 62 | if (ae.ignoreCase) { 63 | ac = true; 64 | } else { 65 | if ( 66 | /[a-z]/i.test(ae.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, '')) 67 | ) { 68 | S = true; 69 | ac = false; 70 | break; 71 | } 72 | } 73 | } 74 | var Y = { b: 8, t: 9, n: 10, v: 11, f: 12, r: 13 }; 75 | function ab(ah) { 76 | var ag = ah.charCodeAt(0); 77 | if (ag !== 92) { 78 | return ag; 79 | } 80 | var af = ah.charAt(1); 81 | ag = Y[af]; 82 | if (ag) { 83 | return ag; 84 | } else { 85 | if ('0' <= af && af <= '7') { 86 | return parseInt(ah.substring(1), 8); 87 | } else { 88 | if (af === 'u' || af === 'x') { 89 | return parseInt(ah.substring(2), 16); 90 | } else { 91 | return ah.charCodeAt(1); 92 | } 93 | } 94 | } 95 | } 96 | function T(af) { 97 | if (af < 32) { 98 | return (af < 16 ? '\\x0' : '\\x') + af.toString(16); 99 | } 100 | var ag = String.fromCharCode(af); 101 | if (ag === '\\' || ag === '-' || ag === '[' || ag === ']') { 102 | ag = '\\' + ag; 103 | } 104 | return ag; 105 | } 106 | function X(am) { 107 | var aq = am 108 | .substring(1, am.length - 1) 109 | .match( 110 | new RegExp( 111 | '\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]', 112 | 'g' 113 | ) 114 | ); 115 | var ak = []; 116 | var af = []; 117 | var ao = aq[0] === '^'; 118 | for (var ar = ao ? 1 : 0, aj = aq.length; ar < aj; ++ar) { 119 | var ah = aq[ar]; 120 | if (/\\[bdsw]/i.test(ah)) { 121 | ak.push(ah); 122 | } else { 123 | var ag = ab(ah); 124 | var al; 125 | if (ar + 2 < aj && '-' === aq[ar + 1]) { 126 | al = ab(aq[ar + 2]); 127 | ar += 2; 128 | } else { 129 | al = ag; 130 | } 131 | af.push([ag, al]); 132 | if (!(al < 65 || ag > 122)) { 133 | if (!(al < 65 || ag > 90)) { 134 | af.push([Math.max(65, ag) | 32, Math.min(al, 90) | 32]); 135 | } 136 | if (!(al < 97 || ag > 122)) { 137 | af.push([Math.max(97, ag) & ~32, Math.min(al, 122) & ~32]); 138 | } 139 | } 140 | } 141 | } 142 | af.sort(function (av, au) { 143 | return av[0] - au[0] || au[1] - av[1]; 144 | }); 145 | var ai = []; 146 | var ap = [NaN, NaN]; 147 | for (var ar = 0; ar < af.length; ++ar) { 148 | var at = af[ar]; 149 | if (at[0] <= ap[1] + 1) { 150 | ap[1] = Math.max(ap[1], at[1]); 151 | } else { 152 | ai.push((ap = at)); 153 | } 154 | } 155 | var an = ['[']; 156 | if (ao) { 157 | an.push('^'); 158 | } 159 | an.push.apply(an, ak); 160 | for (var ar = 0; ar < ai.length; ++ar) { 161 | var at = ai[ar]; 162 | an.push(T(at[0])); 163 | if (at[1] > at[0]) { 164 | if (at[1] + 1 > at[0]) { 165 | an.push('-'); 166 | } 167 | an.push(T(at[1])); 168 | } 169 | } 170 | an.push(']'); 171 | return an.join(''); 172 | } 173 | function W(al) { 174 | var aj = al.source.match( 175 | new RegExp( 176 | '(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)', 177 | 'g' 178 | ) 179 | ); 180 | var ah = aj.length; 181 | var an = []; 182 | for (var ak = 0, am = 0; ak < ah; ++ak) { 183 | var ag = aj[ak]; 184 | if (ag === '(') { 185 | ++am; 186 | } else { 187 | if ('\\' === ag.charAt(0)) { 188 | var af = +ag.substring(1); 189 | if (af && af <= am) { 190 | an[af] = -1; 191 | } 192 | } 193 | } 194 | } 195 | for (var ak = 1; ak < an.length; ++ak) { 196 | if (-1 === an[ak]) { 197 | an[ak] = ++ad; 198 | } 199 | } 200 | for (var ak = 0, am = 0; ak < ah; ++ak) { 201 | var ag = aj[ak]; 202 | if (ag === '(') { 203 | ++am; 204 | if (an[am] === undefined) { 205 | aj[ak] = '(?:'; 206 | } 207 | } else { 208 | if ('\\' === ag.charAt(0)) { 209 | var af = +ag.substring(1); 210 | if (af && af <= am) { 211 | aj[ak] = '\\' + an[am]; 212 | } 213 | } 214 | } 215 | } 216 | for (var ak = 0, am = 0; ak < ah; ++ak) { 217 | if ('^' === aj[ak] && '^' !== aj[ak + 1]) { 218 | aj[ak] = ''; 219 | } 220 | } 221 | if (al.ignoreCase && S) { 222 | for (var ak = 0; ak < ah; ++ak) { 223 | var ag = aj[ak]; 224 | var ai = ag.charAt(0); 225 | if (ag.length >= 2 && ai === '[') { 226 | aj[ak] = X(ag); 227 | } else { 228 | if (ai !== '\\') { 229 | aj[ak] = ag.replace(/[a-zA-Z]/g, function (ao) { 230 | var ap = ao.charCodeAt(0); 231 | return '[' + String.fromCharCode(ap & ~32, ap | 32) + ']'; 232 | }); 233 | } 234 | } 235 | } 236 | } 237 | return aj.join(''); 238 | } 239 | var aa = []; 240 | for (var V = 0, U = Z.length; V < U; ++V) { 241 | var ae = Z[V]; 242 | if (ae.global || ae.multiline) { 243 | throw new Error('' + ae); 244 | } 245 | aa.push('(?:' + W(ae) + ')'); 246 | } 247 | return new RegExp(aa.join('|'), ac ? 'gi' : 'g'); 248 | } 249 | function a(V) { 250 | var U = /(?:^|\s)nocode(?:\s|$)/; 251 | var X = []; 252 | var T = 0; 253 | var Z = []; 254 | var W = 0; 255 | var S; 256 | if (V.currentStyle) { 257 | S = V.currentStyle.whiteSpace; 258 | } else { 259 | if (window.getComputedStyle) { 260 | S = document.defaultView.getComputedStyle(V, null).getPropertyValue('white-space'); 261 | } 262 | } 263 | var Y = S && 'pre' === S.substring(0, 3); 264 | function aa(ab) { 265 | switch (ab.nodeType) { 266 | case 1: 267 | if (U.test(ab.className)) { 268 | return; 269 | } 270 | for (var ae = ab.firstChild; ae; ae = ae.nextSibling) { 271 | aa(ae); 272 | } 273 | var ad = ab.nodeName; 274 | if ('BR' === ad || 'LI' === ad) { 275 | X[W] = '\n'; 276 | Z[W << 1] = T++; 277 | Z[(W++ << 1) | 1] = ab; 278 | } 279 | break; 280 | case 3: 281 | case 4: 282 | var ac = ab.nodeValue; 283 | if (ac.length) { 284 | if (!Y) { 285 | ac = ac.replace(/[ \t\r\n]+/g, ' '); 286 | } else { 287 | ac = ac.replace(/\r\n?/g, '\n'); 288 | } 289 | X[W] = ac; 290 | Z[W << 1] = T; 291 | T += ac.length; 292 | Z[(W++ << 1) | 1] = ab; 293 | } 294 | break; 295 | } 296 | } 297 | aa(V); 298 | return { sourceCode: X.join('').replace(/\n$/, ''), spans: Z }; 299 | } 300 | function B(S, U, W, T) { 301 | if (!U) { 302 | return; 303 | } 304 | var V = { sourceCode: U, basePos: S }; 305 | W(V); 306 | T.push.apply(T, V.decorations); 307 | } 308 | var v = /\S/; 309 | function o(S) { 310 | var V = undefined; 311 | for (var U = S.firstChild; U; U = U.nextSibling) { 312 | var T = U.nodeType; 313 | V = T === 1 ? (V ? S : U) : T === 3 ? (v.test(U.nodeValue) ? S : V) : V; 314 | } 315 | return V === S ? undefined : V; 316 | } 317 | function g(U, T) { 318 | var S = {}; 319 | var V; 320 | (function () { 321 | var ad = U.concat(T); 322 | var ah = []; 323 | var ag = {}; 324 | for (var ab = 0, Z = ad.length; ab < Z; ++ab) { 325 | var Y = ad[ab]; 326 | var ac = Y[3]; 327 | if (ac) { 328 | for (var ae = ac.length; --ae >= 0; ) { 329 | S[ac.charAt(ae)] = Y; 330 | } 331 | } 332 | var af = Y[1]; 333 | var aa = '' + af; 334 | if (!ag.hasOwnProperty(aa)) { 335 | ah.push(af); 336 | ag[aa] = null; 337 | } 338 | } 339 | ah.push(/[\0-\uffff]/); 340 | V = k(ah); 341 | })(); 342 | var X = T.length; 343 | var W = function (ah) { 344 | var Z = ah.sourceCode, 345 | Y = ah.basePos; 346 | var ad = [Y, F]; 347 | var af = 0; 348 | var an = Z.match(V) || []; 349 | var aj = {}; 350 | for (var ae = 0, aq = an.length; ae < aq; ++ae) { 351 | var ag = an[ae]; 352 | var ap = aj[ag]; 353 | var ai = void 0; 354 | var am; 355 | if (typeof ap === 'string') { 356 | am = false; 357 | } else { 358 | var aa = S[ag.charAt(0)]; 359 | if (aa) { 360 | ai = ag.match(aa[1]); 361 | ap = aa[0]; 362 | } else { 363 | for (var ao = 0; ao < X; ++ao) { 364 | aa = T[ao]; 365 | ai = ag.match(aa[1]); 366 | if (ai) { 367 | ap = aa[0]; 368 | break; 369 | } 370 | } 371 | if (!ai) { 372 | ap = F; 373 | } 374 | } 375 | am = ap.length >= 5 && 'lang-' === ap.substring(0, 5); 376 | if (am && !(ai && typeof ai[1] === 'string')) { 377 | am = false; 378 | ap = J; 379 | } 380 | if (!am) { 381 | aj[ag] = ap; 382 | } 383 | } 384 | var ab = af; 385 | af += ag.length; 386 | if (!am) { 387 | ad.push(Y + ab, ap); 388 | } else { 389 | var al = ai[1]; 390 | var ak = ag.indexOf(al); 391 | var ac = ak + al.length; 392 | if (ai[2]) { 393 | ac = ag.length - ai[2].length; 394 | ak = ac - al.length; 395 | } 396 | var ar = ap.substring(5); 397 | B(Y + ab, ag.substring(0, ak), W, ad); 398 | B(Y + ab + ak, al, q(ar, al), ad); 399 | B(Y + ab + ac, ag.substring(ac), W, ad); 400 | } 401 | } 402 | ah.decorations = ad; 403 | }; 404 | return W; 405 | } 406 | function i(T) { 407 | var W = [], 408 | S = []; 409 | if (T.tripleQuotedStrings) { 410 | W.push([ 411 | C, 412 | /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, 413 | null, 414 | '\'"' 415 | ]); 416 | } else { 417 | if (T.multiLineStrings) { 418 | W.push([ 419 | C, 420 | /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/, 421 | null, 422 | '\'"`' 423 | ]); 424 | } else { 425 | W.push([ 426 | C, 427 | /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/, 428 | null, 429 | '"\'' 430 | ]); 431 | } 432 | } 433 | if (T.verbatimStrings) { 434 | S.push([C, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]); 435 | } 436 | var Y = T.hashComments; 437 | if (Y) { 438 | if (T.cStyleComments) { 439 | if (Y > 1) { 440 | W.push([j, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']); 441 | } else { 442 | W.push([ 443 | j, 444 | /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/, 445 | null, 446 | '#' 447 | ]); 448 | } 449 | S.push([ 450 | C, 451 | /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, 452 | null 453 | ]); 454 | } else { 455 | W.push([j, /^#[^\r\n]*/, null, '#']); 456 | } 457 | } 458 | if (T.cStyleComments) { 459 | S.push([j, /^\/\/[^\r\n]*/, null]); 460 | S.push([j, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); 461 | } 462 | if (T.regexLiterals) { 463 | var X = 464 | '/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/'; 465 | S.push(['lang-regex', new RegExp('^' + M + '(' + X + ')')]); 466 | } 467 | var V = T.types; 468 | if (V) { 469 | S.push([O, V]); 470 | } 471 | var U = ('' + T.keywords).replace(/^ | $/g, ''); 472 | if (U.length) { 473 | S.push([z, new RegExp('^(?:' + U.replace(/[\s,]+/g, '|') + ')\\b'), null]); 474 | } 475 | W.push([F, /^\s+/, null, ' \r\n\t\xA0']); 476 | S.push( 477 | [G, /^@[a-z_$][a-z_$@0-9]*/i, null], 478 | [O, /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null], 479 | [F, /^[a-z_$][a-z_$@0-9]*/i, null], 480 | [ 481 | G, 482 | new RegExp( 483 | '^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*', 484 | 'i' 485 | ), 486 | null, 487 | '0123456789' 488 | ], 489 | [F, /^\\[\s\S]?/, null], 490 | [L, /^.[^\s\w\.$@\'\"\`\/\#\\]*/, null] 491 | ); 492 | return g(W, S); 493 | } 494 | var K = i({ 495 | keywords: A, 496 | hashComments: true, 497 | cStyleComments: true, 498 | multiLineStrings: true, 499 | regexLiterals: true 500 | }); 501 | function Q(V, ag) { 502 | var U = /(?:^|\s)nocode(?:\s|$)/; 503 | var ab = /\r\n?|\n/; 504 | var ac = V.ownerDocument; 505 | var S; 506 | if (V.currentStyle) { 507 | S = V.currentStyle.whiteSpace; 508 | } else { 509 | if (window.getComputedStyle) { 510 | S = ac.defaultView.getComputedStyle(V, null).getPropertyValue('white-space'); 511 | } 512 | } 513 | var Z = S && 'pre' === S.substring(0, 3); 514 | var af = ac.createElement('LI'); 515 | while (V.firstChild) { 516 | af.appendChild(V.firstChild); 517 | } 518 | var W = [af]; 519 | function ae(al) { 520 | switch (al.nodeType) { 521 | case 1: 522 | if (U.test(al.className)) { 523 | break; 524 | } 525 | if ('BR' === al.nodeName) { 526 | ad(al); 527 | if (al.parentNode) { 528 | al.parentNode.removeChild(al); 529 | } 530 | } else { 531 | for (var an = al.firstChild; an; an = an.nextSibling) { 532 | ae(an); 533 | } 534 | } 535 | break; 536 | case 3: 537 | case 4: 538 | if (Z) { 539 | var am = al.nodeValue; 540 | var aj = am.match(ab); 541 | if (aj) { 542 | var ai = am.substring(0, aj.index); 543 | al.nodeValue = ai; 544 | var ah = am.substring(aj.index + aj[0].length); 545 | if (ah) { 546 | var ak = al.parentNode; 547 | ak.insertBefore(ac.createTextNode(ah), al.nextSibling); 548 | } 549 | ad(al); 550 | if (!ai) { 551 | al.parentNode.removeChild(al); 552 | } 553 | } 554 | } 555 | break; 556 | } 557 | } 558 | function ad(ak) { 559 | while (!ak.nextSibling) { 560 | ak = ak.parentNode; 561 | if (!ak) { 562 | return; 563 | } 564 | } 565 | function ai(al, ar) { 566 | var aq = ar ? al.cloneNode(false) : al; 567 | var ao = al.parentNode; 568 | if (ao) { 569 | var ap = ai(ao, 1); 570 | var an = al.nextSibling; 571 | ap.appendChild(aq); 572 | for (var am = an; am; am = an) { 573 | an = am.nextSibling; 574 | ap.appendChild(am); 575 | } 576 | } 577 | return aq; 578 | } 579 | var ah = ai(ak.nextSibling, 0); 580 | for (var aj; (aj = ah.parentNode) && aj.nodeType === 1; ) { 581 | ah = aj; 582 | } 583 | W.push(ah); 584 | } 585 | for (var Y = 0; Y < W.length; ++Y) { 586 | ae(W[Y]); 587 | } 588 | if (ag === (ag | 0)) { 589 | W[0].setAttribute('value', ag); 590 | } 591 | var aa = ac.createElement('OL'); 592 | aa.className = 'linenums'; 593 | var X = Math.max(0, (ag - 1) | 0) || 0; 594 | for (var Y = 0, T = W.length; Y < T; ++Y) { 595 | af = W[Y]; 596 | af.className = 'L' + ((Y + X) % 10); 597 | if (!af.firstChild) { 598 | af.appendChild(ac.createTextNode('\xA0')); 599 | } 600 | aa.appendChild(af); 601 | } 602 | V.appendChild(aa); 603 | } 604 | function D(ac) { 605 | var aj = /\bMSIE\b/.test(navigator.userAgent); 606 | var am = /\n/g; 607 | var al = ac.sourceCode; 608 | var an = al.length; 609 | var V = 0; 610 | var aa = ac.spans; 611 | var T = aa.length; 612 | var ah = 0; 613 | var X = ac.decorations; 614 | var Y = X.length; 615 | var Z = 0; 616 | X[Y] = an; 617 | var ar, aq; 618 | for (aq = ar = 0; aq < Y; ) { 619 | if (X[aq] !== X[aq + 2]) { 620 | X[ar++] = X[aq++]; 621 | X[ar++] = X[aq++]; 622 | } else { 623 | aq += 2; 624 | } 625 | } 626 | Y = ar; 627 | for (aq = ar = 0; aq < Y; ) { 628 | var at = X[aq]; 629 | var ab = X[aq + 1]; 630 | var W = aq + 2; 631 | while (W + 2 <= Y && X[W + 1] === ab) { 632 | W += 2; 633 | } 634 | X[ar++] = at; 635 | X[ar++] = ab; 636 | aq = W; 637 | } 638 | Y = X.length = ar; 639 | var ae = null; 640 | while (ah < T) { 641 | var af = aa[ah]; 642 | var S = aa[ah + 2] || an; 643 | var ag = X[Z]; 644 | var ap = X[Z + 2] || an; 645 | var W = Math.min(S, ap); 646 | var ak = aa[ah + 1]; 647 | var U; 648 | if (ak.nodeType !== 1 && (U = al.substring(V, W))) { 649 | if (aj) { 650 | U = U.replace(am, '\r'); 651 | } 652 | ak.nodeValue = U; 653 | var ai = ak.ownerDocument; 654 | var ao = ai.createElement('SPAN'); 655 | ao.className = X[Z + 1]; 656 | var ad = ak.parentNode; 657 | ad.replaceChild(ao, ak); 658 | ao.appendChild(ak); 659 | if (V < S) { 660 | aa[ah + 1] = ak = ai.createTextNode(al.substring(W, S)); 661 | ad.insertBefore(ak, ao.nextSibling); 662 | } 663 | } 664 | V = W; 665 | if (V >= S) { 666 | ah += 2; 667 | } 668 | if (V >= ap) { 669 | Z += 2; 670 | } 671 | } 672 | } 673 | var t = {}; 674 | function c(U, V) { 675 | for (var S = V.length; --S >= 0; ) { 676 | var T = V[S]; 677 | if (!t.hasOwnProperty(T)) { 678 | t[T] = U; 679 | } else { 680 | if (window.console) { 681 | console.warn('cannot override language handler %s', T); 682 | } 683 | } 684 | } 685 | } 686 | function q(T, S) { 687 | if (!(T && t.hasOwnProperty(T))) { 688 | T = /^\s*]*(?:>|$)/], 699 | [j, /^<\!--[\s\S]*?(?:-\->|$)/], 700 | ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/], 701 | ['lang-', /^<%([\s\S]+?)(?:%>|$)/], 702 | [L, /^(?:<[%?]|[%?]>)/], 703 | ['lang-', /^]*>([\s\S]+?)<\/xmp\b[^>]*>/i], 704 | ['lang-js', /^]*>([\s\S]*?)(<\/script\b[^>]*>)/i], 705 | ['lang-css', /^]*>([\s\S]*?)(<\/style\b[^>]*>)/i], 706 | ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i] 707 | ] 708 | ), 709 | ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl'] 710 | ); 711 | c( 712 | g( 713 | [ 714 | [F, /^[\s]+/, null, ' \t\r\n'], 715 | [n, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '"\''] 716 | ], 717 | [ 718 | [m, /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i], 719 | [P, /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], 720 | ['lang-uq.val', /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/], 721 | [L, /^[=<>\/]+/], 722 | ['lang-js', /^on\w+\s*=\s*\"([^\"]+)\"/i], 723 | ['lang-js', /^on\w+\s*=\s*\'([^\']+)\'/i], 724 | ['lang-js', /^on\w+\s*=\s*([^\"\'>\s]+)/i], 725 | ['lang-css', /^style\s*=\s*\"([^\"]+)\"/i], 726 | ['lang-css', /^style\s*=\s*\'([^\']+)\'/i], 727 | ['lang-css', /^style\s*=\s*([^\"\'>\s]+)/i] 728 | ] 729 | ), 730 | ['in.tag'] 731 | ); 732 | c(g([], [[n, /^[\s\S]+/]]), ['uq.val']); 733 | c(i({ keywords: l, hashComments: true, cStyleComments: true, types: e }), [ 734 | 'c', 735 | 'cc', 736 | 'cpp', 737 | 'cxx', 738 | 'cyc', 739 | 'm' 740 | ]); 741 | c(i({ keywords: 'null,true,false' }), ['json']); 742 | c( 743 | i({ 744 | keywords: R, 745 | hashComments: true, 746 | cStyleComments: true, 747 | verbatimStrings: true, 748 | types: e 749 | }), 750 | ['cs'] 751 | ); 752 | c(i({ keywords: x, cStyleComments: true }), ['java']); 753 | c(i({ keywords: H, hashComments: true, multiLineStrings: true }), ['bsh', 'csh', 'sh']); 754 | c(i({ keywords: I, hashComments: true, multiLineStrings: true, tripleQuotedStrings: true }), [ 755 | 'cv', 756 | 'py' 757 | ]); 758 | c(i({ keywords: s, hashComments: true, multiLineStrings: true, regexLiterals: true }), [ 759 | 'perl', 760 | 'pl', 761 | 'pm' 762 | ]); 763 | c(i({ keywords: f, hashComments: true, multiLineStrings: true, regexLiterals: true }), ['rb']); 764 | c(i({ keywords: w, cStyleComments: true, regexLiterals: true }), ['js']); 765 | c( 766 | i({ 767 | keywords: r, 768 | hashComments: 3, 769 | cStyleComments: true, 770 | multilineStrings: true, 771 | tripleQuotedStrings: true, 772 | regexLiterals: true 773 | }), 774 | ['coffee'] 775 | ); 776 | c(g([], [[C, /^[\s\S]+/]]), ['regex']); 777 | function d(V) { 778 | var U = V.langExtension; 779 | try { 780 | var S = a(V.sourceNode); 781 | var T = S.sourceCode; 782 | V.sourceCode = T; 783 | V.spans = S.spans; 784 | V.basePos = 0; 785 | q(U, T)(V); 786 | D(V); 787 | } catch (W) { 788 | if ('console' in window) { 789 | console.log(W && W.stack ? W.stack : W); 790 | } 791 | } 792 | } 793 | function y(W, V, U) { 794 | var S = document.createElement('PRE'); 795 | S.innerHTML = W; 796 | if (U) { 797 | Q(S, U); 798 | } 799 | var T = { langExtension: V, numberLines: U, sourceNode: S }; 800 | d(T); 801 | return S.innerHTML; 802 | } 803 | function b(ad) { 804 | function Y(af) { 805 | return document.getElementsByTagName(af); 806 | } 807 | var ac = [Y('pre'), Y('code'), Y('xmp')]; 808 | var T = []; 809 | for (var aa = 0; aa < ac.length; ++aa) { 810 | for (var Z = 0, V = ac[aa].length; Z < V; ++Z) { 811 | T.push(ac[aa][Z]); 812 | } 813 | } 814 | ac = null; 815 | var W = Date; 816 | if (!W.now) { 817 | W = { 818 | now: function () { 819 | return +new Date(); 820 | } 821 | }; 822 | } 823 | var X = 0; 824 | var S; 825 | var ab = /\blang(?:uage)?-([\w.]+)(?!\S)/; 826 | var ae = /\bprettyprint\b/; 827 | function U() { 828 | var ag = window.PR_SHOULD_USE_CONTINUATION ? W.now() + 250 : Infinity; 829 | for (; X < T.length && W.now() < ag; X++) { 830 | var aj = T[X]; 831 | var ai = aj.className; 832 | if (ai.indexOf('prettyprint') >= 0) { 833 | var ah = ai.match(ab); 834 | var am; 835 | if (!ah && (am = o(aj)) && 'CODE' === am.tagName) { 836 | ah = am.className.match(ab); 837 | } 838 | if (ah) { 839 | ah = ah[1]; 840 | } 841 | var al = false; 842 | for (var ak = aj.parentNode; ak; ak = ak.parentNode) { 843 | if ( 844 | (ak.tagName === 'pre' || 845 | ak.tagName === 'code' || 846 | ak.tagName === 'xmp') && 847 | ak.className && 848 | ak.className.indexOf('prettyprint') >= 0 849 | ) { 850 | al = true; 851 | break; 852 | } 853 | } 854 | if (!al) { 855 | var af = aj.className.match(/\blinenums\b(?::(\d+))?/); 856 | af = af ? (af[1] && af[1].length ? +af[1] : true) : false; 857 | if (af) { 858 | Q(aj, af); 859 | } 860 | S = { langExtension: ah, sourceNode: aj, numberLines: af }; 861 | d(S); 862 | } 863 | } 864 | } 865 | if (X < T.length) { 866 | setTimeout(U, 250); 867 | } else { 868 | if (ad) { 869 | ad(); 870 | } 871 | } 872 | } 873 | U(); 874 | } 875 | window.prettyPrintOne = y; 876 | window.prettyPrint = b; 877 | window.PR = { 878 | createSimpleLexer: g, 879 | registerLangHandler: c, 880 | sourceDecorator: i, 881 | PR_ATTRIB_NAME: P, 882 | PR_ATTRIB_VALUE: n, 883 | PR_COMMENT: j, 884 | PR_DECLARATION: E, 885 | PR_KEYWORD: z, 886 | PR_LITERAL: G, 887 | PR_NOCODE: N, 888 | PR_PLAIN: F, 889 | PR_PUNCTUATION: L, 890 | PR_SOURCE: J, 891 | PR_STRING: C, 892 | PR_TAG: m, 893 | PR_TYPE: O 894 | }; 895 | })(); 896 | PR.registerLangHandler( 897 | PR.createSimpleLexer( 898 | [], 899 | [ 900 | [PR.PR_DECLARATION, /^]*(?:>|$)/], 901 | [PR.PR_COMMENT, /^<\!--[\s\S]*?(?:-\->|$)/], 902 | [PR.PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/], 903 | ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/], 904 | ['lang-', /^<%([\s\S]+?)(?:%>|$)/], 905 | ['lang-', /^]*>([\s\S]+?)<\/xmp\b[^>]*>/i], 906 | [ 907 | 'lang-handlebars', 908 | /^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i 909 | ], 910 | ['lang-js', /^]*>([\s\S]*?)(<\/script\b[^>]*>)/i], 911 | ['lang-css', /^]*>([\s\S]*?)(<\/style\b[^>]*>)/i], 912 | ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i], 913 | [PR.PR_DECLARATION, /^{{[#^>/]?\s*[\w.][^}]*}}/], 914 | [PR.PR_DECLARATION, /^{{&?\s*[\w.][^}]*}}/], 915 | [PR.PR_DECLARATION, /^{{{>?\s*[\w.][^}]*}}}/], 916 | [PR.PR_COMMENT, /^{{![^}]*}}/] 917 | ] 918 | ), 919 | ['handlebars', 'hbs'] 920 | ); 921 | PR.registerLangHandler( 922 | PR.createSimpleLexer( 923 | [[PR.PR_PLAIN, /^[ \t\r\n\f]+/, null, ' \t\r\n\f']], 924 | [ 925 | [PR.PR_STRING, /^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/, null], 926 | [PR.PR_STRING, /^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/, null], 927 | ['lang-css-str', /^url\(([^\)\"\']*)\)/i], 928 | [ 929 | PR.PR_KEYWORD, 930 | /^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i, 931 | null 932 | ], 933 | [ 934 | 'lang-css-kw', 935 | /^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i 936 | ], 937 | [PR.PR_COMMENT, /^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//], 938 | [PR.PR_COMMENT, /^(?:)/], 939 | [PR.PR_LITERAL, /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], 940 | [PR.PR_LITERAL, /^#(?:[0-9a-f]{3}){1,2}/i], 941 | [PR.PR_PLAIN, /^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i], 942 | [PR.PR_PUNCTUATION, /^[^\s\w\'\"]+/] 943 | ] 944 | ), 945 | ['css'] 946 | ); 947 | PR.registerLangHandler( 948 | PR.createSimpleLexer( 949 | [], 950 | [[PR.PR_KEYWORD, /^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]] 951 | ), 952 | ['css-kw'] 953 | ); 954 | PR.registerLangHandler(PR.createSimpleLexer([], [[PR.PR_STRING, /^[^\)\"\']+/]]), ['css-str']); 955 | -------------------------------------------------------------------------------- /app/coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czero1995/miniprogram-cli/e8fe5a7e82f87f0f21f87cb08b91b25833ad43a7/app/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /app/coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var addSorting = (function () { 3 | 'use strict'; 4 | var cols, 5 | currentSort = { 6 | index: 0, 7 | desc: false 8 | }; 9 | 10 | // returns the summary table element 11 | function getTable() { 12 | return document.querySelector('.coverage-summary'); 13 | } 14 | // returns the thead element of the summary table 15 | function getTableHeader() { 16 | return getTable().querySelector('thead tr'); 17 | } 18 | // returns the tbody element of the summary table 19 | function getTableBody() { 20 | return getTable().querySelector('tbody'); 21 | } 22 | // returns the th element for nth column 23 | function getNthColumn(n) { 24 | return getTableHeader().querySelectorAll('th')[n]; 25 | } 26 | 27 | // loads all columns 28 | function loadColumns() { 29 | var colNodes = getTableHeader().querySelectorAll('th'), 30 | colNode, 31 | cols = [], 32 | col, 33 | i; 34 | 35 | for (i = 0; i < colNodes.length; i += 1) { 36 | colNode = colNodes[i]; 37 | col = { 38 | key: colNode.getAttribute('data-col'), 39 | sortable: !colNode.getAttribute('data-nosort'), 40 | type: colNode.getAttribute('data-type') || 'string' 41 | }; 42 | cols.push(col); 43 | if (col.sortable) { 44 | col.defaultDescSort = col.type === 'number'; 45 | colNode.innerHTML = colNode.innerHTML + ''; 46 | } 47 | } 48 | return cols; 49 | } 50 | // attaches a data attribute to every tr element with an object 51 | // of data values keyed by column name 52 | function loadRowData(tableRow) { 53 | var tableCols = tableRow.querySelectorAll('td'), 54 | colNode, 55 | col, 56 | data = {}, 57 | i, 58 | val; 59 | for (i = 0; i < tableCols.length; i += 1) { 60 | colNode = tableCols[i]; 61 | col = cols[i]; 62 | val = colNode.getAttribute('data-value'); 63 | if (col.type === 'number') { 64 | val = Number(val); 65 | } 66 | data[col.key] = val; 67 | } 68 | return data; 69 | } 70 | // loads all row data 71 | function loadData() { 72 | var rows = getTableBody().querySelectorAll('tr'), 73 | i; 74 | 75 | for (i = 0; i < rows.length; i += 1) { 76 | rows[i].data = loadRowData(rows[i]); 77 | } 78 | } 79 | // sorts the table using the data for the ith column 80 | function sortByIndex(index, desc) { 81 | var key = cols[index].key, 82 | sorter = function (a, b) { 83 | a = a.data[key]; 84 | b = b.data[key]; 85 | return a < b ? -1 : a > b ? 1 : 0; 86 | }, 87 | finalSorter = sorter, 88 | tableBody = document.querySelector('.coverage-summary tbody'), 89 | rowNodes = tableBody.querySelectorAll('tr'), 90 | rows = [], 91 | i; 92 | 93 | if (desc) { 94 | finalSorter = function (a, b) { 95 | return -1 * sorter(a, b); 96 | }; 97 | } 98 | 99 | for (i = 0; i < rowNodes.length; i += 1) { 100 | rows.push(rowNodes[i]); 101 | tableBody.removeChild(rowNodes[i]); 102 | } 103 | 104 | rows.sort(finalSorter); 105 | 106 | for (i = 0; i < rows.length; i += 1) { 107 | tableBody.appendChild(rows[i]); 108 | } 109 | } 110 | // removes sort indicators for current column being sorted 111 | function removeSortIndicators() { 112 | var col = getNthColumn(currentSort.index), 113 | cls = col.className; 114 | 115 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 116 | col.className = cls; 117 | } 118 | // adds sort indicators for current column being sorted 119 | function addSortIndicators() { 120 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 121 | } 122 | // adds event listeners for all sorter widgets 123 | function enableUI() { 124 | var i, 125 | el, 126 | ithSorter = function ithSorter(i) { 127 | var col = cols[i]; 128 | 129 | return function () { 130 | var desc = col.defaultDescSort; 131 | 132 | if (currentSort.index === i) { 133 | desc = !currentSort.desc; 134 | } 135 | sortByIndex(i, desc); 136 | removeSortIndicators(); 137 | currentSort.index = i; 138 | currentSort.desc = desc; 139 | addSortIndicators(); 140 | }; 141 | }; 142 | for (i = 0; i < cols.length; i += 1) { 143 | if (cols[i].sortable) { 144 | // add the click event handler on the th so users 145 | // dont have to click on those tiny arrows 146 | el = getNthColumn(i).querySelector('.sorter').parentElement; 147 | if (el.addEventListener) { 148 | el.addEventListener('click', ithSorter(i)); 149 | } else { 150 | el.attachEvent('onclick', ithSorter(i)); 151 | } 152 | } 153 | } 154 | } 155 | // adds sorting functionality to the UI 156 | return function () { 157 | if (!getTable()) { 158 | return; 159 | } 160 | cols = loadColumns(); 161 | loadData(); 162 | addSortIndicators(); 163 | enableUI(); 164 | }; 165 | })(); 166 | 167 | window.addEventListener('load', addSorting); 168 | -------------------------------------------------------------------------------- /app/coverage/lcov-report/util.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for util.js 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files util.js

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 3/3 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 1/1 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 3/3 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 71x 67 | 2x 68 |   69 | 1x 70 |   71 |   72 |  
const add = (num1,num2) => {
73 | 	return num1 + num2
74 | }
75 | module.exports = {
76 | 	add: add
77 | };
78 |  
79 | 80 |
81 |
82 | 87 | 88 | 89 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /app/coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:app/utils/util.js 3 | FN:1,(anonymous_0) 4 | FNF:1 5 | FNH:1 6 | FNDA:2,(anonymous_0) 7 | DA:1,1 8 | DA:2,2 9 | DA:4,1 10 | LF:3 11 | LH:3 12 | BRF:0 13 | BRH:0 14 | end_of_record 15 | -------------------------------------------------------------------------------- /app/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp(); 4 | 5 | Page({ 6 | data: { 7 | motto: 'Hello World', 8 | userInfo: {}, 9 | hasUserInfo: false, 10 | canIUse: wx.canIUse('button.open-type.getUserInfo') 11 | }, 12 | //事件处理函数 13 | bindViewTap: function () { 14 | wx.navigateTo({ 15 | url: '../logs/logs' 16 | }); 17 | }, 18 | onLoad: function () { 19 | if (app.globalData.userInfo) { 20 | this.setData({ 21 | userInfo: app.globalData.userInfo, 22 | hasUserInfo: true 23 | }); 24 | } else if (this.data.canIUse) { 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | app.userInfoReadyCallback = (res) => { 28 | this.setData({ 29 | userInfo: res.userInfo, 30 | hasUserInfo: true 31 | }); 32 | }; 33 | } else { 34 | // 在没有 open-type=getUserInfo 版本的兼容处理 35 | wx.getUserInfo({ 36 | success: (res) => { 37 | app.globalData.userInfo = res.userInfo; 38 | this.setData({ 39 | userInfo: res.userInfo, 40 | hasUserInfo: true 41 | }); 42 | } 43 | }); 44 | } 45 | }, 46 | getUserInfo: function (e) { 47 | console.log(e); 48 | app.globalData.userInfo = e.detail.userInfo; 49 | this.setData({ 50 | userInfo: e.detail.userInfo, 51 | hasUserInfo: true 52 | }); 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /app/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /app/pages/index/index.scss: -------------------------------------------------------------------------------- 1 | .one{ 2 | color:red; 3 | } -------------------------------------------------------------------------------- /app/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{userInfo.nickName}} 8 | 9 | 10 | 11 | {{motto}} 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/pages/one/one.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | /** 3 | * 页面的初始数据 4 | */ 5 | data: {}, 6 | 7 | /** 8 | * 生命周期函数--监听页面加载 9 | */ 10 | onLoad: function (options) {}, 11 | 12 | /** 13 | * 生命周期函数--监听页面初次渲染完成 14 | */ 15 | onReady: function () {}, 16 | 17 | /** 18 | * 生命周期函数--监听页面显示 19 | */ 20 | onShow: function () {}, 21 | 22 | /** 23 | * 生命周期函数--监听页面隐藏 24 | */ 25 | onHide: function () {}, 26 | 27 | /** 28 | * 生命周期函数--监听页面卸载 29 | */ 30 | onUnload: function () {}, 31 | 32 | /** 33 | * 页面相关事件处理函数--监听用户下拉动作 34 | */ 35 | onPullDownRefresh: function () {}, 36 | 37 | /** 38 | * 页面上拉触底事件的处理函数 39 | */ 40 | onReachBottom: function () {}, 41 | 42 | /** 43 | * 用户点击右上角分享 44 | */ 45 | onShareAppMessage: function () {} 46 | }); 47 | -------------------------------------------------------------------------------- /app/pages/one/one.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "Page Name", 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /app/pages/one/one.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | 3 | } -------------------------------------------------------------------------------- /app/pages/one/one.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "preloadBackgroundData": false, 11 | "minified": true, 12 | "newFeature": true, 13 | "autoAudits": false, 14 | "coverView": true, 15 | "showShadowRootInWxmlPanel": true, 16 | "scopeDataCheck": false 17 | }, 18 | "compileType": "miniprogram", 19 | "libVersion": "2.12.1", 20 | "appid": "wxccb505c1dc07c49f", 21 | "projectname": "miniprogram-1", 22 | "debugOptions": { 23 | "hidedInDevtools": [] 24 | }, 25 | "isGameTourist": false, 26 | "simulatorType": "wechat", 27 | "simulatorPluginLibVersion": {}, 28 | "condition": { 29 | "search": { 30 | "current": -1, 31 | "list": [] 32 | }, 33 | "conversation": { 34 | "current": -1, 35 | "list": [] 36 | }, 37 | "game": { 38 | "currentL": -1, 39 | "list": [] 40 | }, 41 | "miniprogram": { 42 | "current": -1, 43 | "list": [] 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /app/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /app/tests/index.test.js: -------------------------------------------------------------------------------- 1 | import { add } from '../utils/util'; 2 | 3 | describe('test utils/util.js', () => { 4 | test('test add', () => { 5 | expect(add(1, 2)).toBe(3); 6 | expect(add(10, 20)).toBe(30); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /app/utils/util.js: -------------------------------------------------------------------------------- 1 | const add = (num1, num2) => { 2 | return num1 + num2; 3 | }; 4 | module.exports = { 5 | add: add 6 | }; 7 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/preset-env', { targets: { node: 'current' } }]], 3 | compact: false 4 | }; 5 | -------------------------------------------------------------------------------- /cli/index.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | const fs = require('fs'); 3 | const chalk = require('chalk'); 4 | const figlet = require('figlet'); 5 | const templatePath = './cli/template'; 6 | const filePath = './app'; 7 | const fileType = ['.wxml', '.js', '.json', '.scss']; 8 | const encoding = 'utf-8'; 9 | const init = () => { 10 | console.log( 11 | chalk.bold.green( 12 | figlet.textSync('MINIAPP CLI', { 13 | horizontalLayout: 'default', 14 | verticalLayout: 'default' 15 | }) 16 | ) 17 | ); 18 | }; 19 | 20 | const askQuestions = () => { 21 | const questions = [ 22 | { 23 | type: 'list', 24 | name: 'Create', 25 | message: '请选择要创建的类型', 26 | choices: ['页面', '组件'] 27 | }, 28 | { 29 | type: 'input', 30 | name: 'Input', 31 | message: '请输入文件名称' 32 | } 33 | ]; 34 | return inquirer.prompt(questions); 35 | }; 36 | 37 | const rsyncData = async (Type, Input) => { 38 | fs.mkdir(`${filePath}/${Type}/${Input}`, (err) => { 39 | if (err) { 40 | console.log(chalk.red(`创建组件失败 --- ${filePath}/${Type}/${Input}组件已存在`)); 41 | return; 42 | } 43 | console.log(chalk.green(`${filePath}/${Type}/${Input}文件夹创建成功`)); 44 | fileType.map((item) => { 45 | fs.readFile(`${templatePath}/${Type}/${Type}${item}`, { encoding }, function ( 46 | err, 47 | msg 48 | ) { 49 | fs.writeFile( 50 | `${filePath}/${Type}/${Input}/${Input}${item}`, 51 | msg, 52 | encoding, 53 | function (error) { 54 | if (error) { 55 | console.log(error); 56 | return false; 57 | } 58 | console.log( 59 | chalk.green(`${filePath}/${Type}/${Input}/${Input}${item}创建成功`) 60 | ); 61 | } 62 | ); 63 | }); 64 | }); 65 | }); 66 | }; 67 | 68 | const run = async () => { 69 | init(); 70 | const answers = await askQuestions(); 71 | const { Create, Input } = answers; 72 | let Type; 73 | switch (Create) { 74 | case '页面': 75 | Type = 'pages'; 76 | break; 77 | case '组件': 78 | Type = 'components'; 79 | break; 80 | } 81 | await rsyncData(Type, Input); 82 | }; 83 | 84 | run(); 85 | -------------------------------------------------------------------------------- /cli/template/components/components.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | // 组件的属性列表 3 | properties: {}, 4 | 5 | // 组件的初始数据 6 | data: {}, 7 | 8 | // 组件的生命周期 9 | lifetimes: { 10 | // 在组件实例刚刚被创建时执行 11 | created() {}, 12 | // 在组件实例进入页面节点树时执行 13 | attached() {}, 14 | // 在组件在视图层布局完成后执行 15 | ready() {}, 16 | // 在组件实例被从页面节点树移除时执行 17 | detached() {} 18 | }, 19 | 20 | // 组件的方法列表 21 | methods: {} 22 | }); 23 | -------------------------------------------------------------------------------- /cli/template/components/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /cli/template/components/components.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | 3 | } -------------------------------------------------------------------------------- /cli/template/components/components.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /cli/template/pages/pages.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | /** 3 | * 页面的初始数据 4 | */ 5 | data: {}, 6 | 7 | /** 8 | * 生命周期函数--监听页面加载 9 | */ 10 | onLoad: function (options) {}, 11 | 12 | /** 13 | * 生命周期函数--监听页面初次渲染完成 14 | */ 15 | onReady: function () {}, 16 | 17 | /** 18 | * 生命周期函数--监听页面显示 19 | */ 20 | onShow: function () {}, 21 | 22 | /** 23 | * 生命周期函数--监听页面隐藏 24 | */ 25 | onHide: function () {}, 26 | 27 | /** 28 | * 生命周期函数--监听页面卸载 29 | */ 30 | onUnload: function () {}, 31 | 32 | /** 33 | * 页面相关事件处理函数--监听用户下拉动作 34 | */ 35 | onPullDownRefresh: function () {}, 36 | 37 | /** 38 | * 页面上拉触底事件的处理函数 39 | */ 40 | onReachBottom: function () {}, 41 | 42 | /** 43 | * 用户点击右上角分享 44 | */ 45 | onShareAppMessage: function () {} 46 | }); 47 | -------------------------------------------------------------------------------- /cli/template/pages/pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "Page Name", 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /cli/template/pages/pages.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | 3 | } -------------------------------------------------------------------------------- /cli/template/pages/pages.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czero1995/miniprogram-cli/e8fe5a7e82f87f0f21f87cb08b91b25833ad43a7/img/github.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ['/tests/**/*.js'], 3 | testEnvironment: 'node', 4 | rootDir: './app', 5 | moduleFileExtensions: ['js'], 6 | coveragePathIgnorePatterns: ['/assets/', '/network/'] 7 | }; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "miniprogram-cli", 3 | "version": "1.0.0", 4 | "description": "miniprogram-cli", 5 | "author": "czero1995", 6 | "main": "webpack.config.js", 7 | "scripts": { 8 | "dev": "webpack", 9 | "img": "webpack --config webpack.compress", 10 | "create": "node ./cli", 11 | "test:watch": "jest --watch", 12 | "test": "jest --coverage", 13 | "precommit": "lint-staged --allow-empty" 14 | }, 15 | "husky": { 16 | "hooks": { 17 | "pre-commit": "lint-staged" 18 | } 19 | }, 20 | "lint-staged": { 21 | "*.{js,wxss}": [ 22 | "eslint --fix", 23 | "prettier --write" 24 | ] 25 | }, 26 | "devDependencies": { 27 | "@babel/plugin-transform-modules-commonjs": "^7.10.4", 28 | "@babel/preset-env": "^7.11.0", 29 | "babel-eslint": "^10.1.0", 30 | "chalk": "^4.1.0", 31 | "css-loader": "^3.5.3", 32 | "eslint": "^6.8.0", 33 | "figlet": "^1.5.0", 34 | "file-loader": "^6.0.0", 35 | "fs": "^0.0.1-security", 36 | "globby": "^9.2.0", 37 | "husky": "^4.2.5", 38 | "image-webpack-loader": "^6.0.0", 39 | "jest": "^26.4.2", 40 | "lint-staged": "^10.2.7", 41 | "mini-css-extract-plugin": "^0.4.5", 42 | "node-sass": "^4.14.1", 43 | "prettier": "^2.0.5", 44 | "sass-loader": "^7.3.1", 45 | "url-loader": "^4.1.0", 46 | "webpack": "^4.29.6", 47 | "webpack-cli": "^3.3.11", 48 | "webpack-fix-style-only-entries": "^0.2.1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /webpack.compress.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const glob = require('globby'); 3 | const chalk = require('chalk'); 4 | const figlet = require('figlet'); 5 | 6 | const ENTRY_PATH = { 7 | pattern: ['img/**/*.{jpg,JPG,jpeg,JPEG,png,svg,gif}'], 8 | app: path.join(__dirname, 'app') 9 | }; 10 | 11 | const getEntryPath = (config) => { 12 | const fileList = glob.sync(config.pattern); 13 | return fileList.reduce((previous, current) => { 14 | const filePath = path.parse(path.relative(config.app, current)); 15 | const withoutSuffix = path.join(filePath.dir, filePath.name); 16 | previous[withoutSuffix] = path.resolve(__dirname, current); 17 | return previous; 18 | }, {}); 19 | }; 20 | 21 | const init = () => { 22 | console.log( 23 | chalk.bold.green( 24 | figlet.textSync('MINIAPP CLI', { 25 | horizontalLayout: 'default', 26 | verticalLayout: 'default' 27 | }) 28 | ) 29 | ); 30 | }; 31 | 32 | let config = { 33 | entry: getEntryPath(ENTRY_PATH), 34 | output: { 35 | path: __dirname 36 | }, 37 | mode: 'production', 38 | watch: true, 39 | watchOptions: { 40 | ignored: ['cli/**', 'node_modules/**'] 41 | }, 42 | module: { 43 | rules: [ 44 | { 45 | test: /\.(png|svg|jpg|gif)$/, 46 | use: [ 47 | { 48 | loader: 'file-loader', 49 | options: { 50 | name: '[path][name].[ext]', 51 | publicPath: 'app/assets', 52 | outputPath: 'app/assets' 53 | } 54 | }, 55 | { 56 | loader: 'image-webpack-loader', 57 | options: { 58 | pngquant: { 59 | quality: [0.6, 0.9], 60 | speed: 4 61 | } 62 | } 63 | } 64 | ] 65 | } 66 | ] 67 | } 68 | }; 69 | init(); 70 | module.exports = config; 71 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const glob = require('globby'); 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries'); 5 | const chalk = require('chalk'); 6 | const figlet = require('figlet'); 7 | 8 | const ENTRY_PATH = { 9 | pattern: ['app/pages/**/*.scss', 'app/components/**/*.scss', 'app/app.scss'], 10 | app: path.join(__dirname, 'app') 11 | }; 12 | 13 | const getEntryPath = (config) => { 14 | const fileList = glob.sync(config.pattern); 15 | return fileList.reduce((previous, current) => { 16 | const filePath = path.parse(path.relative(config.app, current)); 17 | const withoutSuffix = path.join(filePath.dir, filePath.name); 18 | previous[withoutSuffix] = path.resolve(__dirname, current); 19 | return previous; 20 | }, {}); 21 | }; 22 | 23 | const config = { 24 | entry: getEntryPath(ENTRY_PATH), 25 | output: { 26 | path: __dirname 27 | }, 28 | mode: 'production', 29 | watch: true, 30 | watchOptions: { 31 | ignored: ['cli/**', 'node_modules/**'] 32 | }, 33 | module: { 34 | rules: [ 35 | { 36 | test: /\.(scss)$/, 37 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'] 38 | } 39 | ] 40 | }, 41 | plugins: [ 42 | new FixStyleOnlyEntriesPlugin(), 43 | new MiniCssExtractPlugin({ 44 | filename: '/app/[name].wxss' 45 | }) 46 | ], 47 | resolve: { 48 | extensions: ['.scss'] 49 | } 50 | }; 51 | const init = () => { 52 | console.log( 53 | chalk.bold.green( 54 | figlet.textSync('MINIAPP CLI', { 55 | horizontalLayout: 'default', 56 | verticalLayout: 'default' 57 | }) 58 | ) 59 | ); 60 | }; 61 | init(); 62 | module.exports = config; 63 | --------------------------------------------------------------------------------