├── .gitignore
├── .gitignore.bak
├── README.md
├── css
└── layout.css
├── index.html
├── js
├── controller.js
├── dto
│ └── ClassModel.js
├── repository
│ ├── DBUtil.js
│ ├── TableDao.js
│ └── TableEntity.js
├── service.js
├── templateFileLoader.js
├── util
│ ├── $.js
│ ├── Assert.js
│ ├── yi.template.js
│ └── yi.toast.js
└── vm
│ ├── DBProfileVM.js
│ └── GenerateVM.js
├── main.js
├── package-lock.json
├── package.json
└── template
└── Entity.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /out
3 |
--------------------------------------------------------------------------------
/.gitignore.bak:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # database2java
--------------------------------------------------------------------------------
/css/layout.css:
--------------------------------------------------------------------------------
1 | article,header,footer,section,aside,main,
2 | figcaption,figure,
3 | fieldset,p,div{
4 | box-sizing: border-box;
5 | display: block;
6 | }
7 | h1,h2{
8 | margin: 0;
9 | }
10 | .center{
11 | text-align: center;
12 | }
13 | .layout-hbox {
14 | display: flex;
15 | flex-direction: row;
16 | flex-wrap: nowrap;
17 | justify-content: flex-start;
18 | align-items: stretch;
19 | }
20 |
21 | .layout-hbox > .grow {
22 | flex: auto;
23 | }
24 | .layout-hbox-center {
25 | display: flex;
26 | flex-direction: row;
27 | flex-wrap: nowrap;
28 | justify-content:flex-start;
29 | align-items:center;
30 | }
31 |
32 | .layout-hbox-center > .grow {
33 | flex: auto;
34 | }
35 | .layout-justify {
36 | display: flex;
37 | flex-flow: row nowrap;
38 | justify-content: space-between;
39 | align-items: center;
40 | }
41 | .layout-justify-stretch{
42 | display: flex;
43 | flex-flow: row wrap;
44 | justify-content: space-between;
45 | align-items: stretch;
46 | }
47 | .layout-middle {
48 | display: flex;
49 | align-items: center;
50 | justify-content: space-between;
51 | }
52 | .layout-vbox {
53 | display: flex;
54 | flex-direction: column;
55 | flex-wrap: nowrap;
56 | justify-content: flex-start;
57 | align-items: stretch;
58 | }
59 |
60 | .layout-vbox > .grow {
61 | flex: auto;
62 | overflow: auto;
63 | }
64 |
65 |
66 |
67 | table.data {
68 | width: 100%;
69 | border-collapse: collapse;
70 | text-align: center;
71 | }
72 |
73 | table.data th {
74 | border: 1px solid #81b4be;
75 | padding: 5px 0;
76 | }
77 |
78 | table.data td{
79 | border: 1px solid #ccc;
80 | padding: 5px 5px;
81 | }
82 |
83 | table.data > thead>tr {
84 | background-color: hsl(243,30%,50%);
85 | font-weight: bold;
86 | height: 2em;
87 | color:#ffffff;
88 | }
89 |
90 | table.data>tr,table.data>tbody>tr {
91 | background-color: #ffffff;
92 | color:hsl(0,0%,5%)
93 | }
94 |
95 |
96 |
97 | table.data>tr:nth-child(even),table.data>tbody>tr:nth-child(even) {
98 | background-color: hsl(60,50%,97%);
99 | }
100 |
101 | table.data>tr:HOVER,table.data>tbody>tr:HOVER {
102 | background-color: hsl(60,50%,90%);
103 | color:hsl(0,0%,0%)
104 | }
105 | button, .btn{
106 | border: 1px solid #204d74;
107 | border-radius: 4px;
108 | background: #286090 none;
109 | color: #eeeeff;
110 | cursor: pointer;
111 | font-size: 100%;
112 | font-family: sans-serif, "宋体";
113 | font-weight: bold;
114 | line-height: 1.15;
115 | overflow: hidden;
116 | box-sizing: border-box;
117 | padding: 8px 15px;
118 | margin: 0;
119 | }
120 |
121 |
122 | button:HOVER, .btn:HOVER {
123 | color: #ffffff;
124 | background-color: #df2e1b;
125 | border-color: #c42818;
126 | }
127 |
128 | button:ACTIVE, .btn:ACTIVE {
129 | color: #ffffff;
130 | background-color: #2f2f2f;
131 | border-bottom-color: #eee;
132 | border-right-color: #eee;
133 | }
134 |
135 | button[disabled], [disabled].btn {
136 | cursor: wait;
137 | color: #eeeeff;
138 | background-color: gray;
139 | border-color: #204d74;
140 | }
141 |
142 |
143 |
144 | a.btn {
145 | text-decoration: none;
146 | display: inline-block;
147 | vertical-align: middle;
148 | text-align: center;
149 | }
150 |
151 | /**两个按钮有距离*/
152 | button + button,
153 | button + .btn,
154 | .btn + button,
155 | .btn + .btn {
156 | margin-left: 1em;
157 | }
158 |
159 | button.D3, .btn.D3 {
160 | background-color: #DB5705;
161 | border-radius: 8px;
162 | box-shadow: 0px 9px 0px rgba(219, 31, 5, 1), 0px 9px 25px rgba(0, 0, 0, .7);
163 | transition: all .1s ease;
164 | }
165 |
166 | .D3:HOVER {
167 | background-color: #D56f0B;
168 | }
169 |
170 |
171 | input[type="text"],
172 | input[type="password"],
173 | input[type="number"],
174 | input[type="datetime-local"],
175 | input[type="date"],
176 | input[type="email"],
177 | input[type="url"],
178 | input[type="tel"],
179 | select,
180 | textarea {
181 | box-sizing: border-box;
182 | display: inline-block;
183 | vertical-align: middle;
184 | font-size: 100%;
185 | color: #555;
186 | background-color: #fff;
187 | border: 1px solid #ccc;
188 | border-radius: 4px;
189 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
190 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
191 | -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
192 | -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
193 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
194 | padding-left: .5em;
195 | line-height: 1.15;
196 | min-height: 40px;
197 | min-width:0;
198 | width:auto;
199 | font-family: "Microsoft YaHei", 微软雅黑, "MicrosoftJhengHei";
200 | }
201 | input:focus, textarea:focus,select:focus {
202 | border-color: #66afe9;
203 | outline: 0;
204 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6);
205 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, .6);
206 | }
207 |
208 | input:hover, textarea:hover,select:hover {
209 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 133, .6);
210 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 133, .6);
211 | }
212 |
213 | input[readonly], textarea[readonly],select[readonly]{
214 | background: #eeeeee;
215 | color: #000;
216 | }
217 |
218 | input[disabled], textarea[disabled],select[disabled]{
219 | background: #F0FFFF !important;
220 | color: #808080; !important;
221 | }
222 |
223 | textarea {
224 | padding-right: .5em;
225 | text-indent: 0;
226 | vertical-align: top;
227 | }
228 |
229 | [type="number"]::-webkit-inner-spin-button,
230 | [type="number"]::-webkit-outer-spin-button {
231 | height: auto;
232 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DB2Java
6 |
7 |
41 |
42 |
43 |
44 | DataBase生成Java源代码
45 |
46 |
76 |
77 |
78 |
请选择要生成的表
79 |
80 |
81 |
82 | #
83 | | 表名 |
84 | 类名 |
85 |
86 |
87 |
88 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | 下划线分隔列名转换为
114 |
118 |
119 |
datetime转换为
120 |
125 |
timestamp转换为
126 |
131 |
date转换为
132 |
137 |
138 |
139 |
140 |
141 | 类包名:
142 |
143 |
144 |
145 |
146 | 存放目录:
147 |
148 |
151 |
152 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/js/controller.js:
--------------------------------------------------------------------------------
1 | const DBProfileVM = require("./js/vm/DBProfileVM");
2 | const GenerateVM = require("./js/vm/GenerateVM");
3 | const service=require("./js/service");
4 |
5 | //当前dbProfile
6 | let currentDBProfile;
7 |
8 |
9 | //连接数据库按钮点击事件处理
10 | $("#connectionBtn").addEventListener("click", function(evt) {
11 | this.disabled=true;
12 | //加载视图模型
13 | try{
14 | currentDBProfile=DBProfileVM.load();
15 | }catch(e){
16 | this.disabled=false;
17 | toast(e);
18 | return;
19 | }
20 | //加载表
21 | service.loadDatabaseTableNames(currentDBProfile)
22 | .then(function(tables){
23 | //计算出对应类名
24 | let result=tables.map(t=>{
25 | return {
26 | tableName:t,
27 | //首字母要大写
28 | className:$.underline2camelcasing(t,true)
29 | }
30 | });
31 |
32 | $("#table-list-view-tbody").innerHTML=paintTablesList(result);
33 |
34 | }).catch(err=>{
35 | if(err.errno==="ECONNREFUSED"){
36 | alert("数据库拒绝连接,请检查数据库配置");
37 | }else{
38 | alert(err);
39 | }
40 | }).finally(()=>{
41 | this.disabled=false;
42 | });
43 |
44 | });
45 |
46 | /**
47 | * 表名行添加事件监听
48 | */
49 | $("#table-list-view-tbody").addEventListener("click", function(evt) {
50 | evt.stopPropagation();
51 | let target = evt.target;
52 | if (target.tagName === "TD") {
53 | let checkBox = target.parentNode.getElementsByTagName("input")[0];
54 | if(checkBox.checked){
55 | checkBox.checked=false;
56 | }else{
57 | checkBox.checked=true;
58 | }
59 | }
60 |
61 | });
62 |
63 | /**
64 | * 执行按钮
65 | */
66 | $("#action-btn").addEventListener("click",function(evt){
67 | //1 禁用按钮
68 | this.disabled=true;
69 | //2 任务输入对象
70 | let generateVM;
71 | try{
72 | //从视图加载生成文件参数的ViewModel对象
73 | generateVM=GenerateVM.load();
74 | }catch(e){
75 | toast(e.message);
76 | this.disabled=false;
77 | }
78 | //异步开启任务
79 | service.generateFiles(currentDBProfile,generateVM).then(function(taskResults){
80 | alert("生成完毕,共生成"+taskResults.length+"个文件");
81 | }).catch(function(e){
82 | console.log(e);
83 | alert(e.message);
84 | }).finally(()=>{
85 | this.disabled=false;
86 | });
87 | });
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/js/dto/ClassModel.js:
--------------------------------------------------------------------------------
1 | const Assert=require("../util/Assert");
2 | function ClassModel(){
3 | this.imports=[];
4 | this.packageName;
5 | this.className;
6 | this.fields=[];
7 | }
8 | ClassModel.prototype.addField=function(f){
9 | this.fields.push(f);
10 | //1 获取字段全类型
11 | let fullType=f.fullType;
12 | //2 截取包名
13 | let typePackageEndIndex=fullType.lastIndexOf('.');
14 | if(typePackageEndIndex!=-1){
15 | let typePackage=fullType.substring(0,typePackageEndIndex);
16 | if(typePackage!=="java.lang"){
17 | if(!this.imports[typePackage]){
18 | this.imports[typePackage]=true;
19 | this.imports.push(typePackage);
20 | }
21 | }
22 | }
23 | }
24 |
25 |
26 | function FieldModel(){
27 | //列类型描述
28 | this.columnType;
29 | //java类型全限定类名
30 | this.fullType;
31 | //java类型名称(无包名)
32 | this.simpleType;
33 | //字段名称
34 | this.name;
35 |
36 | this.defaultValue;
37 | this.comment;
38 | };
39 | FieldModel.prototype.setName=function(name,options){
40 | if(options["underlineOption"]==="camel"){
41 | this.name=$.underline2camelcasing(name);
42 | }else{
43 | this.name=name;
44 | }
45 | }
46 | //设置
47 | FieldModel.prototype.setColumnType=function(columnType,options){
48 |
49 | this.columnType=columnType;
50 | //2 去掉类型中的小括号
51 | let endIndex=columnType.lastIndexOf('(');
52 | columnType=columnType.substring(0,endIndex===-1?columnType.length:endIndex);
53 |
54 | //3 得到转换规则
55 | const mapping=Object.assign({},FieldModel.TYPE_MAPPING,options);
56 | console.log(mapping);
57 |
58 | //4 得到java类型
59 | this.simpleType=this.fullType=mapping[columnType.toLowerCase()];
60 |
61 | //5 截取简单java类型
62 | let simpleTypeEndIndex=this.fullType.lastIndexOf('.');
63 | if(simpleTypeEndIndex!==-1){
64 | this.simpleType=this.fullType.substr(simpleTypeEndIndex+1);
65 | }
66 | }
67 |
68 |
69 | FieldModel.TYPE_MAPPING={
70 | "bit":"boolean",
71 | "tinyint":"int",
72 | "smallint":"int",
73 | "mediumint":"int",
74 | "int":"int",
75 | "integer":"int",
76 | "bigint":"int",
77 | "double":"double",
78 | "float":"float",
79 | "decimal":"double",
80 | "numeric":"double",
81 |
82 | "date":"java.time.LocalDate",
83 | "time":"java.time.LocalTime",
84 | "year":"int",
85 | "timestamp":"java.time.LocalDateTime",
86 | "datetime":"java.time.LocalDateTime",
87 |
88 | "char":"java.lang.String",
89 | "varchar":"java.lang.String",
90 | "tinytext":"java.lang.String",
91 | "text":"java.lang.String",
92 | "mediumint":"java.lang.String",
93 | "longtext":"java.lang.String"
94 |
95 |
96 |
97 | }
98 |
99 | module.exports={ClassModel,FieldModel};
--------------------------------------------------------------------------------
/js/repository/DBUtil.js:
--------------------------------------------------------------------------------
1 | const mysql = require("mysql");
2 | /*
3 | */
4 | let DBUtil=function(){};
5 |
6 | let currentProfile;
7 | let connection;
8 |
9 |
10 | DBUtil.getConnection=function(profile){
11 | if(!profile){
12 | throw new Error("无法获取连接,无profile");
13 | }
14 | //同一个profile
15 | if(profile.equals(currentProfile)){
16 | //判断是否关闭
17 | if(connection&&connection.state==="connected"){
18 | return connection;
19 | }
20 |
21 | }
22 | currentProfile=profile;
23 | return connection=mysql.createConnection({
24 | host:profile.host||"127.0.0.1",
25 | port:profile.port||3306,
26 | database:profile.database,
27 | user:profile.username,
28 | password:profile.password
29 | });
30 | };
31 |
32 | module.exports=DBUtil;
--------------------------------------------------------------------------------
/js/repository/TableDao.js:
--------------------------------------------------------------------------------
1 | const DBUtil=require("../repository/DBUtil");
2 | const {TableEntity,TableColumnEntity}=require("../repository/TableEntity");
3 |
4 | function TableDao(profile){
5 | this.profile=profile;
6 | }
7 |
8 |
9 | TableDao.prototype.selectColumnsByTable=function(tableName){
10 | let profile=this.profile;
11 | return new Promise(function(ok,fail){
12 | let sql =`SELECT
13 | column_name as columnName,
14 | column_default as defaultValue,
15 | column_type as columnType,
16 | column_comment as comment
17 | FROM information_schema.COLUMNS
18 | WHERE
19 | table_schema =?
20 | AND table_name =?
21 | order by ORDINAL_POSITION`;
22 | let connection=DBUtil.getConnection(profile);
23 |
24 |
25 | connection.query(sql, [profile.database,tableName], function(err, rows) {
26 | if(err){
27 | fail(err);
28 | connection.destory();
29 | }else{
30 | let columns=[];
31 | for(let i=0;i t["tableName"]));
53 | }
54 | });
55 |
56 | });
57 | };
58 |
59 |
60 | let row2entity=function(row){
61 | const e=new TableColumnEntity();
62 | e.name=row["columnName"];
63 | e.dataType=row["columnType"];
64 | e.defaultValue=row["defaultValue"];
65 | e.comment=row["comment"];
66 | return e;
67 | }
68 |
69 | module.exports=TableDao;
--------------------------------------------------------------------------------
/js/repository/TableEntity.js:
--------------------------------------------------------------------------------
1 | function TableEntity(){
2 | this.name;
3 | this.columns;
4 | }
5 |
6 | function TableColumnEntity(){
7 | this.name;
8 | this.dataType;
9 | this.defaultValue;
10 | this.comment;
11 | }
12 |
13 | module.exports={TableEntity,TableColumnEntity};
--------------------------------------------------------------------------------
/js/service.js:
--------------------------------------------------------------------------------
1 | const TableDao=require("./repository/TableDao");
2 | const {ClassModel,FieldModel}=require("./dto/ClassModel");
3 | const templateFileLoader=require("./templateFileLoader");
4 | const fs = require("fs");
5 | const path = require("path");
6 |
7 | //模板文件内容生成方法
8 | let templateFileFunctions={};
9 |
10 | try{
11 | const templateFiles=templateFileLoader.load();
12 | for(let f in templateFiles){
13 | templateFileFunctions[f]=new TemplateFunction(f+"(m)",templateFiles[f]).build();
14 | }
15 | console.log(templateFileFunctions);
16 | }catch(e){
17 | console.error(e);
18 | alert("无法加载模板文件,请检查template目录下文件");
19 | }
20 | /**
21 | * 通过数据库名称查找表名称
22 | */
23 | const loadDatabaseTableNames=function(profile){
24 | let dao=new TableDao(profile);
25 | return dao.selectTables();
26 | };
27 |
28 | /**
29 | * 生成文件
30 | */
31 | let generateFiles=function(profileVM,generateVM){
32 | let dao=new TableDao(profileVM);
33 | //所有异步任务
34 | let allTask=[];
35 | //遍历表
36 | for(let table of generateVM.tableNames){
37 | //添加异步任务
38 | allTask.push(new Promise(function(ok,fail){
39 |
40 | dao.selectColumnsByTable(table).then(function(columns){
41 | try{
42 | generateClassFile(generateVM,table,columns);
43 | ok(1);
44 | }catch(e){
45 | fail(e);
46 | }
47 | }).catch(fail);
48 | }));
49 | }
50 |
51 | return Promise.all(allTask);
52 | };
53 | /**
54 | * 生成模板文件
55 | */
56 | const generateClassFile=function(generateModel,tableName,columns){
57 | const classModel=new ClassModel();
58 |
59 | //2 package
60 | classModel.packageName=generateModel.packageName;
61 | //3 className
62 | classModel.className=generateModel.getClassNameByTableName(tableName);
63 | //4 fields
64 | for(let col of columns){
65 | classModel.addField(column2field(col,generateModel));
66 | }
67 | // 5 创建存放包目录
68 | let saveDir=generateModel.fileSaveDir;
69 | saveDir+="/"+classModel.packageName.replace(".","/");
70 | mkdirsSync(saveDir);
71 |
72 | //6 获取模板
73 | for(let f in templateFileFunctions){
74 | const fileContents=templateFileFunctions[f].call(window,classModel);
75 | let fileName=saveDir+"/"+classModel.className+".java";
76 | fs.writeFileSync(fileName,fileContents,{encoding:"utf-8"});
77 | }
78 | }
79 |
80 | const mkdirsSync=function(file){
81 | if(fs.existsSync(file)){
82 | return;
83 | }
84 | mkdirsSync(path.dirname(file));
85 | fs.mkdirSync(file,{recursive:true});
86 | }
87 |
88 | const column2field=function(col,generateModel){
89 | const f=new FieldModel();
90 | f.setName(col.name,generateModel.generateOptions);
91 | f.setColumnType(col.dataType,generateModel.mappingOptions);
92 | f.comment=col.comment;
93 | f.defaultValue=col.defaultValue;
94 | return f;
95 | }
96 |
97 | module.exports={loadDatabaseTableNames,generateFiles};
98 |
99 |
--------------------------------------------------------------------------------
/js/templateFileLoader.js:
--------------------------------------------------------------------------------
1 | const fs=require("fs");
2 | const TEMPLATE_FILE_DIRECTORY="./template";
3 |
4 | const templateFiles={};
5 |
6 | const load=function(){
7 | fs.readdirSync(TEMPLATE_FILE_DIRECTORY).forEach(function(f){
8 | //6 读取模板
9 | const bytes=fs.readFileSync(TEMPLATE_FILE_DIRECTORY+"/"+f,'utf8');
10 | templateFiles[f]=bytes;
11 | });
12 |
13 | return templateFiles;
14 | }
15 | module.exports={
16 | load
17 | };
18 |
--------------------------------------------------------------------------------
/js/util/$.js:
--------------------------------------------------------------------------------
1 | let $=function(str,ctx=document){
2 | let result=ctx.querySelectorAll(str);
3 | if(result.length===0)return null;
4 | if(result.length===1)return result[0];
5 | return result;
6 | };
7 |
8 | $.assertNotBlank=function(el,message){
9 |
10 | };
11 | $.upperFirstLetter=function(s){
12 | let cs=s.split("");
13 | let c=cs[0];
14 | if('a'<=c&&c<='z'){
15 | cs[0]=c.toUpperCase();
16 | }
17 | return cs.join("");
18 | }
19 | /**
20 | * 下划线分别改为驼峰命名法
21 | */
22 | $.underline2camelcasing=function(s,upperFirstLetter){
23 | let parts=s.split("_");
24 | let end=upperFirstLetter?0:1;
25 | for(let i=parts.length;i-- >end;){
26 | parts[i]=$.upperFirstLetter(parts[i]);
27 | }
28 | return parts.join("");
29 | }
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/js/util/Assert.js:
--------------------------------------------------------------------------------
1 | function Assert(){}
2 |
3 |
4 | Assert.stringNotBlank=function(message,s){
5 | if(typeof s==='undefined'
6 | ||s===null
7 | ||(s=s.trim()).length===0
8 | ){
9 | throw new Error(message);
10 | }
11 | return s;
12 | };
13 |
14 | Assert.arrayNotEmpty=function(message,arr){
15 | if(typeof arr==='undefined'
16 | ||arr===null
17 | ||arr.length===0
18 | ){
19 | throw new Error(message);
20 | }
21 | return arr;
22 | };
23 |
24 | module.exports=Assert;
--------------------------------------------------------------------------------
/js/util/yi.template.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | /**
3 | * @param {String} nameAndArgs 方法声明为xxx(a,b)
4 | * @param {String} templateSource 字符串模板
5 | */
6 | let TemplateFunction =window.TemplateFunction= function (nameAndArgs, templateSource) {
7 | //方法声明格式为xxx或xxx(a,b)
8 | this.nameAndArgs = nameAndArgs;
9 | //模板字符串
10 | this.templateSource = templateSource;
11 | //模板方法名称
12 | this.functionName=null;
13 | //模板方法参数
14 | this.functionArgumentNames=null;
15 | //模板方法体
16 | this.body = [];
17 | //生成方法引用
18 | this.functionReference=null;
19 |
20 | privateMethod.init.apply(this);
21 | };
22 | //私有方法
23 | let privateMethod = {
24 | init: function () {
25 | //解析
26 | let result = staticMethod.parseFunctionNameAndArgumentNames(this.nameAndArgs);
27 | this.functionName = result[0];
28 | this.functionArgumentNames = result[1];
29 | }
30 | };
31 | //方法中的
32 | TemplateFunction.helper={
33 | print:function(s,ds){
34 | if(s===null||s===undefined)return ds||'';
35 | return String(s);
36 | },
37 | escapePrint:function(s,ds){
38 | if(s===null||s===undefined)return ds||'';
39 | return String(s).replace(/[<>&]/g, function (c) {
40 | return {'<': '<', '>': '>', '&': '&'}[c]
41 | })
42 | }
43 | };
44 | /**
45 | * 公开方法
46 | */
47 | TemplateFunction.prototype = {
48 | //构建模板方法
49 | build: function () {
50 |
51 | let out = this.body;
52 | //添加工具方法
53 | out.push("let helper=window.TemplateFunction.helper,");
54 | out.push("$=helper.print,");
55 | out.push("_='';\n");
56 | //添加try-finally保证模板方法返回值
57 | out.push("try{\n");
58 |
59 | //构建方法体
60 | out.parseCode = staticMethod.parseCode;
61 | out.parseText = staticMethod.parseText;
62 | out.parseExpInText = staticMethod.parseExpInText;
63 | out.parseExpInCode=staticMethod.parseExpInCode;
64 | out.parseTemplate=staticMethod.parseTemplate;
65 |
66 | out.parseTemplate(this.templateSource,0);
67 | //添加finally保证模板方法返回值
68 | out.push("\n}catch(e){console.log(e)}finally{return _;}");
69 |
70 | let funBody = out.join("");
71 | let args = this.functionArgumentNames;
72 | try {
73 | //创建方法
74 | let f = args ? new Function(args, funBody) : new Function(funBody);
75 | this.functionReference=f;
76 | return f;
77 | } catch (e) {
78 | console.log(e);
79 | console.log(funBody);
80 | }
81 | }
82 |
83 | };
84 |
85 | let staticMethod = {
86 | parseFunctionNameAndArgumentNames: function (funName) {
87 | let begin = funName.indexOf("(");
88 | if (begin === -1) {
89 | return [funName, null];
90 | } else {
91 | return [funName.substring(0, begin), funName.substring(begin + 1, funName.lastIndexOf(")"))];
92 | }
93 | },
94 | parseTemplate:function(template,begin){
95 | let textBeginIndex =-1;
96 | for (let i = begin, z = template.length,c; i < z; i++) {
97 | c = template.charAt(i);
98 | if(c==='<'&&template.charAt(i + 1) === '-'){
99 | let codeBeginIndex = i + 2;
100 | let codeEndIndex=codeBeginIndex;
101 | //find the code end
102 | for(;codeEndIndex') {
105 | //handle the text
106 | if (textBeginIndex>=0) {
107 | if(textBeginIndex!==i){
108 | this.parseText(template.substring(textBeginIndex, i));
109 | textBeginIndex=-1;
110 | }
111 | }
112 | this.parseCode(template.substring(codeBeginIndex, codeEndIndex),0);
113 |
114 | return this.parseTemplate(template,codeEndIndex+2);
115 | }
116 | }
117 | }else if(c==='$'&&template.charAt(i + 1) === '('){
118 | let expBeginIndex = i + 2;
119 | let expEndIndex=expBeginIndex;
120 | let nestingExpCount=1;
121 | //find the code end
122 | for(;expEndIndex=0) {
133 | if(textBeginIndex!==i){
134 | this.parseText(template.substring(textBeginIndex, i));
135 | textBeginIndex=-1;
136 | }
137 | }
138 | this.parseExpInText(template.substring(expBeginIndex, expEndIndex));
139 | this.parseTemplate(template,expEndIndex+1);
140 | return;
141 | }
142 | }
143 | }
144 | }else{
145 | if(textBeginIndex===-1){
146 | textBeginIndex=i;
147 | }
148 | }
149 | }//end for
150 | },
151 |
152 | parseCode: function (code,begin) {
153 | let codeBeginIndex =-1;
154 | for (let i= begin, z = code.length,c; i < z; i++) {
155 | c = code.charAt(i);
156 | if(c==='$'&&code.charAt(i + 1) === '('){
157 | let expBeginIndex = i + 2;
158 | let expEndIndex=expBeginIndex;
159 | let nestingExpCount=1;
160 | //find the code end
161 | for(;expEndIndex=0) {
170 | if(codeBeginIndex!==i){
171 | this.push(code.substring(codeBeginIndex, i));
172 | codeBeginIndex=-1;
173 | }
174 | }
175 | this.parseExpInCode(code.substring(expBeginIndex, expEndIndex));
176 | return this.parseCode(code,expEndIndex+1);
177 | }
178 | }
179 | }
180 |
181 | }else{
182 | if(codeBeginIndex===-1){
183 | codeBeginIndex=i;
184 | }
185 | }
186 | }
187 | if (codeBeginIndex>=0) {
188 | this.push(code.substr(codeBeginIndex));
189 | }
190 | },
191 |
192 | parseExpInText: function (exp) {
193 | this.push("_+=$(" + exp + ");");
194 | },
195 | parseExpInCode:function (exp) {
196 | this.push("_+=$(" + exp + ")");
197 | },
198 | parseText: function (txt) {
199 | //双引号转义
200 | txt = txt.replace(/"/g, '\\"');
201 | //换行符分割
202 | const lines = txt.split(/\r?\n/);
203 | if (lines.length > 0) {
204 | let i = 0, z = lines.length - 1;
205 | while (i < z) {
206 | //一行一行输出,每行多输出一个换行
207 | this.push('_+="' + lines[i++] + '\\r\\n";\n');
208 | }
209 | this.push('_+="' + lines[z] + '";');
210 | }
211 | }
212 |
213 | };
214 |
215 |
216 | window.addEventListener("load",function(){
217 | //通过