Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DiDi
Chameleon
提交
acbdc105
C
Chameleon
项目概览
DiDi
/
Chameleon
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
Chameleon
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
acbdc105
编写于
5月 16, 2019
作者:
B
beatles-chameleon
提交者:
GitHub
5月 16, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #179 from didi/0.4.x-dev-yyl
0.4.x dev yyl
上级
5c4c3689
67372cea
变更
20
隐藏空白更改
内联
并排
Showing
20 changed file
with
647 addition
and
353 deletion
+647
-353
packages/chameleon-tool/configs/getCommonConfig.js
packages/chameleon-tool/configs/getCommonConfig.js
+1
-4
packages/chameleon-tool/configs/mvvm/getExtendConfig.js
packages/chameleon-tool/configs/mvvm/getExtendConfig.js
+26
-2
packages/chameleon-tool/configs/mvvm/originSourceLoader.js
packages/chameleon-tool/configs/mvvm/originSourceLoader.js
+7
-0
packages/chameleon-tool/configs/mvvm/styleWrapLoader.js
packages/chameleon-tool/configs/mvvm/styleWrapLoader.js
+0
-33
packages/chameleon-tool/configs/mvvm/utils.js
packages/chameleon-tool/configs/mvvm/utils.js
+0
-1
packages/interface-loader/src/index.js
packages/interface-loader/src/index.js
+0
-7
packages/mvvm-interface-parser/lib/check.js
packages/mvvm-interface-parser/lib/check.js
+3
-302
packages/mvvm-interface-parser/runtime/checkWrapper.js
packages/mvvm-interface-parser/runtime/checkWrapper.js
+296
-0
packages/mvvm-interface-parser/test/checkWrapper.test.js
packages/mvvm-interface-parser/test/checkWrapper.test.js
+73
-0
packages/mvvm-pack/cmlNode.js
packages/mvvm-pack/cmlNode.js
+2
-1
packages/mvvm-pack/compiler.js
packages/mvvm-pack/compiler.js
+4
-0
packages/mvvm-pack/lib/amdbootstrap.module.js
packages/mvvm-pack/lib/amdbootstrap.module.js
+1
-1
packages/mvvm-pack/package.json
packages/mvvm-pack/package.json
+2
-1
packages/mvvm-pack/test/cmlNode.test.js
packages/mvvm-pack/test/cmlNode.test.js
+27
-0
packages/mvvm-pack/test/lib/amd.test.js
packages/mvvm-pack/test/lib/amd.test.js
+32
-0
packages/mvvm-pack/test/lib/amdbootstrap.global.test.js
packages/mvvm-pack/test/lib/amdbootstrap.global.test.js
+21
-0
packages/mvvm-pack/test/lib/amdbootstrap.module.test.js
packages/mvvm-pack/test/lib/amdbootstrap.module.test.js
+39
-0
packages/mvvm-pack/test/lib/amdwrapper.test.js
packages/mvvm-pack/test/lib/amdwrapper.test.js
+1
-1
packages/mvvm-pack/test/lib/replaceJsModId.test.js
packages/mvvm-pack/test/lib/replaceJsModId.test.js
+75
-0
packages/mvvm-template-parser/test/index.test.js
packages/mvvm-template-parser/test/index.test.js
+37
-0
未找到文件。
packages/chameleon-tool/configs/getCommonConfig.js
浏览文件 @
acbdc105
...
...
@@ -38,7 +38,6 @@ module.exports = function (options) {
publicPath
=
`http://
${
config
.
ip
}
:
${
webServerPort
}
/
${
type
}
/`
}
let
commonConfig
=
{
stats
:
cml
.
logLevel
===
'
debug
'
?
'
verbose
'
:
'
none
'
,
output
:
{
...
...
@@ -79,9 +78,7 @@ module.exports = function (options) {
options
:
{
'
filename
'
:
path
.
join
(
cml
.
root
,
'
chameleon.js
'
)
}
}
]
}]
},
{
test
:
/
\.(
png|jpe
?
g|gif|svg
)(\?
.*
)?
$/
,
...
...
packages/chameleon-tool/configs/mvvm/getExtendConfig.js
浏览文件 @
acbdc105
...
...
@@ -4,6 +4,9 @@ const getCommonConfig = require('../getCommonConfig');
const
utils
=
require
(
'
../utils.js
'
);
const
{
MvvmGraphPlugin
}
=
require
(
'
mvvm-pack
'
);
const
resolve
=
require
(
'
resolve
'
);
const
originSourceLoader
=
{
loader
:
path
.
join
(
__dirname
,
'
./originSourceLoader.js
'
)
};
module
.
exports
=
function
(
options
)
{
let
{
type
,
media
}
=
options
;
...
...
@@ -15,6 +18,15 @@ module.exports = function(options) {
media
});
cml
.
extPlatformPlugin
[
type
]
=
platformPlugin
;
function
getCmlLoaders
()
{
let
loaders
=
utils
.
cssLoaders
({
type
,
media
});
loaders
.
js
=
[
loaders
.
js
,
originSourceLoader
]
return
loaders
;
}
let
extendConfig
=
{
entry
:
{
app
:
path
.
join
(
cml
.
projectRoot
,
'
src/app/app.cml
'
)
...
...
@@ -30,7 +42,7 @@ module.exports = function(options) {
use
:
[{
loader
:
'
mvvm-cml-loader
'
,
options
:
{
loaders
:
utils
.
cssLoaders
({
type
,
media
}
),
loaders
:
getCmlLoaders
(
),
cmlType
:
type
,
media
,
check
:
cml
.
config
.
get
().
check
...
...
@@ -46,13 +58,25 @@ module.exports = function(options) {
},
platformPlugin
)
]
};
// options.moduleIdType = 'hash';
let
commonConfig
=
getCommonConfig
(
options
);
commonConfig
.
module
.
rules
.
forEach
(
item
=>
{
// 静态资源的处理
if
(
~
[
'
chameleon-url-loader
'
,
'
file-loader
'
].
indexOf
(
item
.
loader
))
{
item
.
loader
=
'
mvvm-file-loader
'
;
item
.
options
.
publicPath
=
commonConfig
.
output
.
publicPath
}
if
(
item
.
test
instanceof
RegExp
)
{
// interface获取originSource
if
(
item
.
test
.
test
(
'
name.interface
'
))
{
item
.
use
.
splice
(
1
,
0
,
originSourceLoader
)
}
// js获取originSource
if
(
item
.
test
.
test
(
'
name.js
'
))
{
item
.
use
.
push
(
originSourceLoader
)
}
}
})
// 用户可以扩展webpack的rules用于处理特有文件后缀
...
...
packages/chameleon-tool/configs/mvvm/originSourceLoader.js
0 → 100644
浏览文件 @
acbdc105
/**
* js 模块获取节点源代码,在interface-loader处理后 babel-loader前
*/
module
.
exports
=
function
(
output
)
{
this
.
_module
.
_cmlOriginSource
=
output
;
return
output
;
}
packages/chameleon-tool/configs/mvvm/styleWrapLoader.js
已删除
100644 → 0
浏览文件 @
5c4c3689
/** 为style模块包装 防止webpack build moudle error */
module
.
exports
=
function
(
content
)
{
this
.
_module
.
_nodeType
=
'
module
'
;
this
.
_module
.
_moduleType
=
'
style
'
;
this
.
_module
.
_cmlSource
=
content
;
return
`module.exports =
${
JSON
.
stringify
(
content
)}
`
}
const
postcss
=
require
(
'
postcss
'
);
module
.
exports
=
function
({
source
,
filePath
,
compiler
})
{
let
deps
=
[];
const
assetsPlugin
=
postcss
.
plugin
(
'
postcss-assets-plugin
'
,
function
(
options
)
{
return
(
root
,
result
)
=>
{
root
.
walkDecls
((
decl
,
i
)
=>
{
if
(
~
decl
.
value
.
indexOf
(
'
url
'
))
{
decl
.
value
=
decl
.
value
.
replace
(
/url
\s
*
\(\s
*
[\'\"]?(
.+
?)[\'\"]?\s
*
\)
/g
,
function
(
all
,
$1
)
{
let
realDependPath
=
compiler
.
resolve
(
filePath
,
$1
);
deps
.
push
(
realDependPath
);
let
publicPath
=
compiler
.
getPublicPath
(
realDependPath
);
return
publicPath
;
})
}
})
}
})
return
{
source
:
postcss
([
assetsPlugin
]).
process
(
source
).
css
,
deps
}
}
packages/chameleon-tool/configs/mvvm/utils.js
已删除
100644 → 0
浏览文件 @
5c4c3689
packages/interface-loader/src/index.js
浏览文件 @
acbdc105
const
loaderUtils
=
require
(
'
loader-utils
'
)
const
mvvmInterfaceParser
=
require
(
'
mvvm-interface-parser
'
);
const
path
=
require
(
'
path
'
)
module
.
exports
=
function
(
source
)
{
const
rawOptions
=
loaderUtils
.
getOptions
(
this
);
const
options
=
rawOptions
||
{};
// loader的类型 wx web weex
let
{
cmlType
,
media
,
check
=
{}}
=
options
;
const
filePath
=
this
.
resourcePath
;
let
self
=
this
;
const
resolve
=
function
(
filePath
,
relativePath
)
{
let
context
=
path
.
dirname
(
filePath
);
self
.
resolveSync
(
context
,
relativePath
);
}
// todo
let
{
result
,
devDeps
}
=
mvvmInterfaceParser
({
cmlType
,
media
,
source
,
filePath
,
check
});
devDeps
.
forEach
(
item
=>
{
...
...
packages/mvvm-interface-parser/lib/check.js
浏览文件 @
acbdc105
...
...
@@ -20,7 +20,7 @@ const handlExport = function (ast) {
// 拿到 new Method(); 这一段代码
let
declarationCode
=
generate
[
"
default
"
](
path
.
node
.
declaration
);
// 得到 export default __OBJECT__WARPPER__(new Method());
let
codeSeg
=
exportCode
.
code
.
replace
(
declarationCode
.
code
,
'
__OBJECT__WRAPPER__(
'
+
declarationCode
.
code
+
'
)
'
);
let
codeSeg
=
exportCode
.
code
.
replace
(
declarationCode
.
code
,
'
__OBJECT__WRAPPER__(
'
+
declarationCode
.
code
+
'
, __CML_ERROR__, __enableTypes__, __CHECK__DEFINES__
)
'
);
// 转成ast
let
replacement
=
parser
.
parse
(
codeSeg
,
{
plugins
:
parsePlugins
,
...
...
@@ -37,303 +37,6 @@ const handlExport = function (ast) {
return
ast
;
};
/**
* 对象包裹器
*运行时的错误信息,根据端传入不同的方法,
* @param {Object} obj 需要处理的对象
* @return {Object} 对象
*/
/* istanbul ignore next */
const
wrapper
=
function
(
obj
)
{
const
className
=
obj
.
constructor
.
name
;
/* eslint-disable no-undef */
const
defines
=
__CHECK__DEFINES__
;
const
enableTypes
=
__enableTypes__
.
split
(
'
,
'
)
||
[];
// ['Object','Array','Nullable']
/* eslint-disable no-undef */
const
types
=
defines
.
types
;
const
interfaceNames
=
defines
.
classes
[
className
];
const
methods
=
{};
interfaceNames
&&
interfaceNames
.
forEach
(
interfaceName
=>
{
const
keys
=
Object
.
keys
(
defines
.
interfaces
);
keys
.
forEach
(
key
=>
{
Object
.
assign
(
methods
,
defines
.
interfaces
[
key
]);
});
});
/**
* 获取类型
*
* @param {*} value 值
* @return {string} 类型
*/
const
getType
=
function
(
value
)
{
if
(
value
instanceof
Promise
)
{
return
"
Promise
"
;
}
const
type
=
Object
.
prototype
.
toString
.
call
(
value
);
return
type
.
replace
(
/
\[
object
\s(
.*
)\]
/g
,
'
$1
'
).
replace
(
/
(
|^
)[
a-z
]
/g
,
(
L
)
=>
L
.
toUpperCase
());
};
/**
* 校验类型 两个loader共用代码
*
* @param {*} value 实际传入的值
* @param {string} type 静态分析时候得到的值得类型
* @param {array[string]} errList 校验错误信息 类型
* @return {bool} 校验结果
*/
/* eslint complexity:[2,39] */
const
checkType
=
function
(
value
,
originType
,
errList
=
[])
{
let
isNullableReg
=
/_cml_nullable_lmc_/g
;
let
type
=
originType
.
replace
(
'
_cml_nullable_lmc_
'
,
''
);
(
type
===
"
Void
"
)
&&
(
type
=
"
Undefined
"
)
let
currentType
=
getType
(
value
);
let
canUseNullable
=
enableTypes
.
includes
(
"
Nullable
"
);
let
canUseObject
=
enableTypes
.
includes
(
"
Object
"
);
if
(
currentType
==
'
Null
'
)
{
if
(
type
==
"
Null
"
)
{
// 如果定义的参数的值就是 Null,那么校验通过
errList
=
[];
}
else
{
// 那么判断是否是可选参数的情况
(
canUseNullable
&&
isNullableReg
.
test
(
originType
))
?
errList
=
[]
:
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请确认是否开启nullable配置`
)
}
return
errList
;
}
if
(
currentType
==
'
Undefined
'
)
{
// 如果运行时传入的真实值是undefined,那么可能改值在接口处就是被定义为 Undefined类型或者是 ?string 这种可选参数 nullable的情况;
if
(
type
==
"
Undefined
"
)
{
errList
=
[];
}
else
{
(
canUseNullable
&&
isNullableReg
.
test
(
originType
))
?
errList
=
[]
:
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请确认是否开启nullable配置或者检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
String
'
)
{
if
(
type
==
'
String
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Boolean
'
)
{
if
(
type
==
'
Boolean
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Number
'
)
{
if
(
type
==
'
Number
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Object
'
)
{
if
(
type
==
'
Object
'
)
{
(
!
canUseObject
)
?
errList
.
push
(
`不能直接定义类型
${
type
}
,需要使用符合类型定义,请确认是否开启了可以直接定义 Object 类型参数;`
)
:
(
errList
=
[]);
}
else
if
(
type
==
'
CMLObject
'
)
{
errList
=
[];
}
else
{
// 这种情况的对象就是自定义的对象;
if
(
types
[
type
])
{
const
keys
=
Object
.
keys
(
types
[
type
]);
// todo 这里是同样的问题,可能多传递
keys
.
forEach
(
key
=>
{
let
subError
=
checkType
(
value
[
key
],
types
[
type
][
key
],
[]);
if
(
subError
&&
subError
.
length
)
{
errList
=
errList
.
concat
(
subError
)
}
});
if
(
Object
.
keys
(
value
).
length
>
keys
.
length
)
{
errList
.
push
(
`type [
${
type
}
] 参数个数与定义不符`
)
}
}
else
{
errList
.
push
(
'
找不到定义的type [
'
+
type
+
'
]!
'
);
}
}
return
errList
;
}
if
(
currentType
==
'
Array
'
)
{
if
(
type
==
'
Array
'
)
{
(
!
canUseObject
)
?
errList
.
push
(
`不能直接定义类型
${
type
}
,需要使用符合类型定义,请确认是否开启了可以直接定义 Array 类型参数;`
)
:
(
errList
=
[]);
}
else
{
if
(
types
[
type
])
{
// 数组元素的类型
let
itemType
=
types
[
type
][
0
];
for
(
let
i
=
0
;
i
<
value
.
length
;
i
++
)
{
let
subError
=
checkType
(
value
[
i
],
itemType
,
[]);
if
(
subError
&&
subError
.
length
)
{
errList
=
errList
.
concat
(
subError
)
}
}
}
else
{
errList
.
push
(
'
找不到定义的type [
'
+
type
+
'
]!
'
);
}
}
return
errList
;
}
if
(
currentType
==
'
Function
'
)
{
// if (type == 'Function') {
// errList = [];
// } else {
// errList.push(`定义了${type}类型的参数,传入的却是${currentType},请检查所传参数是否和接口定义的一致`)
// }
if
(
types
[
type
])
{
if
(
!
types
[
type
].
input
&&
!
types
[
type
].
output
)
{
errList
.
push
(
`找不到
${
types
[
type
]}
函数定义的输入输出`
);
}
}
else
{
errList
.
push
(
'
找不到定义的type [
'
+
type
+
'
]!
'
);
}
return
errList
;
}
if
(
currentType
==
'
Promise
'
)
{
if
(
type
==
'
Promise
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Date
'
)
{
if
(
type
==
'
Date
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
RegExp
'
)
{
if
(
type
==
'
RegExp
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
return
errList
;
}
/**
* 校验参数类型
*
* @param {string} methodName 方法名称
* @param {Array} argNames 参数名称列表
* @param {Array} argValues 参数值列表
* @return {bool} 校验结果
*/
const
checkArgsType
=
function
(
methodName
,
argValues
)
{
let
argList
;
if
(
getType
(
methodName
)
==
'
Array
'
)
{
// 回调函数的校验 methodName[0] 方法的名字 methodName[1]该回调函数在方法的参数索引
argList
=
types
[
methods
[
methodName
[
0
]].
input
[
methodName
[
1
]]].
input
;
// 拿到这个回调函数的参数定义
}
else
{
argList
=
methods
[
methodName
].
input
;
}
// todo 函数可能多传参数
argList
.
forEach
((
argType
,
index
)
=>
{
let
errList
=
checkType
(
argValues
[
index
],
argType
,
[]);
if
(
errList
&&
errList
.
length
>
0
)
{
showErrorMessage
(
`
校验位置: 方法
${
methodName
}
第
${
index
+
1
}
个参数
错误信息:
${
errList
.
join
(
'
\n
'
)}
`
)
}
});
if
(
argValues
.
length
>
argList
.
length
)
{
showErrorMessage
(
`[
${
methodName
}
]方法参数传递个数与定义不符`
);
}
};
/**
* 校验返回值类型
*
* @param {string} methodName 方法名称
* @param {*} returnData 返回值
* @return {bool} 校验结果
*/
const
checkReturnType
=
function
(
methodName
,
returnData
)
{
let
output
;
if
(
getType
(
methodName
)
==
'
Array
'
)
{
output
=
types
[
methods
[
methodName
[
0
]].
input
[
methodName
[
1
]]].
output
;
}
else
{
output
=
methods
[
methodName
].
output
;
}
// todo output 为什么可以是数组
// if (output instanceof Array) {
// output.forEach(type => {
// //todo 而且是要有一个校验不符合就check失败? 应该是有一个校验通过就可以吧
// checkType(returnData, type,[])
// });
// }
let
errList
=
checkType
(
returnData
,
output
,
[]);
if
(
errList
&&
errList
.
length
>
0
)
{
showErrorMessage
(
`
校验位置: 方法
${
methodName
}
返回值
错误信息:
${
errList
.
join
(
'
\n
'
)}
`
)
}
};
/**
* 创建warpper
*
* @param {string} funcName 方法名称
* @param {Function} originFunc 原有方法
* @return {Function} 包裹后的方法
*/
const
createWarpper
=
function
(
funcName
,
originFunc
)
{
return
function
()
{
const
argValues
=
Array
.
prototype
.
slice
.
call
(
arguments
)
.
map
(
function
(
arg
,
index
)
{
// 对传入的方法要做特殊的处理,这个是传入的callback,对callback函数再做包装
if
(
getType
(
arg
)
==
'
Function
'
)
{
return
createWarpper
([
funcName
,
index
],
arg
);
}
return
arg
;
});
checkArgsType
(
funcName
,
argValues
);
const
result
=
originFunc
.
apply
(
this
,
argValues
);
checkReturnType
(
funcName
,
result
)
return
result
;
}
};
// 获取所有方法
const
keys
=
Object
.
keys
(
methods
);
// 处理包装方法
keys
.
forEach
(
key
=>
{
const
originFunc
=
obj
[
key
];
if
(
!
originFunc
)
{
showErrorMessage
(
'
method [
'
+
key
+
'
] not found!
'
);
return
;
}
if
(
obj
.
hasOwnProperty
(
key
))
{
obj
[
key
]
=
createWarpper
(
key
,
originFunc
);
}
else
{
Object
.
getPrototypeOf
(
obj
)[
key
]
=
createWarpper
(
key
,
originFunc
);
}
});
return
obj
;
};
/**
* 获取处理后的代码
*
...
...
@@ -376,10 +79,8 @@ const getCode = function (code, options) {
const __CML_ERROR__ =
${
throwError
.
toString
()}
`
}
/* eslint-disable no-inner-declarations */
wrapperCode
=
`
${
wrapper
.
toString
().
replace
(
/showErrorMessage/g
,
'
__CML_ERROR__
'
)}
`
const
wrapperPath
=
path
.
join
(
__dirname
,
'
../runtime/checkWrapper.js
'
);
wrapperCode
=
`require('
${
cmlUtils
.
handleRelativePath
(
filePath
,
wrapperPath
)}
')`
result
+=
`
const __enableTypes__ = "
${
enableTypes
}
"
...
...
packages/mvvm-interface-parser/runtime/checkWrapper.js
0 → 100644
浏览文件 @
acbdc105
/**
* 对象包裹器
*运行时的错误信息,根据端传入不同的方法,
* @param {Object} obj 需要处理的对象
* @return {Object} 对象
*/
/* istanbul ignore next */
module
.
exports
=
function
(
obj
,
__CML_ERROR__
,
__enableTypes__
,
__CHECK__DEFINES__
)
{
const
className
=
obj
.
constructor
.
name
;
/* eslint-disable no-undef */
const
defines
=
__CHECK__DEFINES__
;
const
enableTypes
=
__enableTypes__
.
split
(
'
,
'
)
||
[];
// ['Object','Array','Nullable']
/* eslint-disable no-undef */
const
types
=
defines
.
types
;
const
interfaceNames
=
defines
.
classes
[
className
];
const
methods
=
{};
interfaceNames
&&
interfaceNames
.
forEach
(
interfaceName
=>
{
const
keys
=
Object
.
keys
(
defines
.
interfaces
);
keys
.
forEach
(
key
=>
{
Object
.
assign
(
methods
,
defines
.
interfaces
[
key
]);
});
});
/**
* 获取类型
*
* @param {*} value 值
* @return {string} 类型
*/
const
getType
=
function
(
value
)
{
if
(
value
instanceof
Promise
)
{
return
"
Promise
"
;
}
const
type
=
Object
.
prototype
.
toString
.
call
(
value
);
return
type
.
replace
(
/
\[
object
\s(
.*
)\]
/g
,
'
$1
'
).
replace
(
/
(
|^
)[
a-z
]
/g
,
(
L
)
=>
L
.
toUpperCase
());
};
/**
* 校验类型 两个loader共用代码
*
* @param {*} value 实际传入的值
* @param {string} type 静态分析时候得到的值得类型
* @param {array[string]} errList 校验错误信息 类型
* @return {bool} 校验结果
*/
/* eslint complexity:[2,39] */
const
checkType
=
function
(
value
,
originType
,
errList
=
[])
{
let
isNullableReg
=
/_cml_nullable_lmc_/g
;
let
type
=
originType
.
replace
(
'
_cml_nullable_lmc_
'
,
''
);
(
type
===
"
Void
"
)
&&
(
type
=
"
Undefined
"
)
let
currentType
=
getType
(
value
);
let
canUseNullable
=
enableTypes
.
includes
(
"
Nullable
"
);
let
canUseObject
=
enableTypes
.
includes
(
"
Object
"
);
if
(
currentType
==
'
Null
'
)
{
if
(
type
==
"
Null
"
)
{
// 如果定义的参数的值就是 Null,那么校验通过
errList
=
[];
}
else
{
// 那么判断是否是可选参数的情况
(
canUseNullable
&&
isNullableReg
.
test
(
originType
))
?
errList
=
[]
:
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请确认是否开启nullable配置`
)
}
return
errList
;
}
if
(
currentType
==
'
Undefined
'
)
{
// 如果运行时传入的真实值是undefined,那么可能改值在接口处就是被定义为 Undefined类型或者是 ?string 这种可选参数 nullable的情况;
if
(
type
==
"
Undefined
"
)
{
errList
=
[];
}
else
{
(
canUseNullable
&&
isNullableReg
.
test
(
originType
))
?
errList
=
[]
:
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请确认是否开启nullable配置或者检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
String
'
)
{
if
(
type
==
'
String
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Boolean
'
)
{
if
(
type
==
'
Boolean
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Number
'
)
{
if
(
type
==
'
Number
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Object
'
)
{
if
(
type
==
'
Object
'
)
{
(
!
canUseObject
)
?
errList
.
push
(
`不能直接定义类型
${
type
}
,需要使用符合类型定义,请确认是否开启了可以直接定义 Object 类型参数;`
)
:
(
errList
=
[]);
}
else
if
(
type
==
'
CMLObject
'
)
{
errList
=
[];
}
else
{
// 这种情况的对象就是自定义的对象;
if
(
types
[
type
])
{
const
keys
=
Object
.
keys
(
types
[
type
]);
// todo 这里是同样的问题,可能多传递
keys
.
forEach
(
key
=>
{
let
subError
=
checkType
(
value
[
key
],
types
[
type
][
key
],
[]);
if
(
subError
&&
subError
.
length
)
{
errList
=
errList
.
concat
(
subError
)
}
});
if
(
Object
.
keys
(
value
).
length
>
keys
.
length
)
{
errList
.
push
(
`type [
${
type
}
] 参数个数与定义不符`
)
}
}
else
{
errList
.
push
(
'
找不到定义的type [
'
+
type
+
'
]!
'
);
}
}
return
errList
;
}
if
(
currentType
==
'
Array
'
)
{
if
(
type
==
'
Array
'
)
{
(
!
canUseObject
)
?
errList
.
push
(
`不能直接定义类型
${
type
}
,需要使用符合类型定义,请确认是否开启了可以直接定义 Array 类型参数;`
)
:
(
errList
=
[]);
}
else
{
if
(
types
[
type
])
{
// 数组元素的类型
let
itemType
=
types
[
type
][
0
];
for
(
let
i
=
0
;
i
<
value
.
length
;
i
++
)
{
let
subError
=
checkType
(
value
[
i
],
itemType
,
[]);
if
(
subError
&&
subError
.
length
)
{
errList
=
errList
.
concat
(
subError
)
}
}
}
else
{
errList
.
push
(
'
找不到定义的type [
'
+
type
+
'
]!
'
);
}
}
return
errList
;
}
if
(
currentType
==
'
Function
'
)
{
// if (type == 'Function') {
// errList = [];
// } else {
// errList.push(`定义了${type}类型的参数,传入的却是${currentType},请检查所传参数是否和接口定义的一致`)
// }
if
(
types
[
type
])
{
if
(
!
types
[
type
].
input
&&
!
types
[
type
].
output
)
{
errList
.
push
(
`找不到
${
types
[
type
]}
函数定义的输入输出`
);
}
}
else
{
errList
.
push
(
'
找不到定义的type [
'
+
type
+
'
]!
'
);
}
return
errList
;
}
if
(
currentType
==
'
Promise
'
)
{
if
(
type
==
'
Promise
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
Date
'
)
{
if
(
type
==
'
Date
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
if
(
currentType
==
'
RegExp
'
)
{
if
(
type
==
'
RegExp
'
)
{
errList
=
[];
}
else
{
errList
.
push
(
`定义了
${
type
}
类型的参数,传入的却是
${
currentType
}
,请检查所传参数是否和接口定义的一致`
)
}
return
errList
;
}
return
errList
;
}
/**
* 校验参数类型
*
* @param {string} methodName 方法名称
* @param {Array} argNames 参数名称列表
* @param {Array} argValues 参数值列表
* @return {bool} 校验结果
*/
const
checkArgsType
=
function
(
methodName
,
argValues
)
{
let
argList
;
if
(
getType
(
methodName
)
==
'
Array
'
)
{
// 回调函数的校验 methodName[0] 方法的名字 methodName[1]该回调函数在方法的参数索引
argList
=
types
[
methods
[
methodName
[
0
]].
input
[
methodName
[
1
]]].
input
;
// 拿到这个回调函数的参数定义
}
else
{
argList
=
methods
[
methodName
].
input
;
}
// todo 函数可能多传参数
argList
.
forEach
((
argType
,
index
)
=>
{
let
errList
=
checkType
(
argValues
[
index
],
argType
,
[]);
if
(
errList
&&
errList
.
length
>
0
)
{
__CML_ERROR__
(
`
校验位置: 方法
${
methodName
}
第
${
index
+
1
}
个参数
错误信息:
${
errList
.
join
(
'
\n
'
)}
`
)
}
});
if
(
argValues
.
length
>
argList
.
length
)
{
__CML_ERROR__
(
`[
${
methodName
}
]方法参数传递个数与定义不符`
);
}
};
/**
* 校验返回值类型
*
* @param {string} methodName 方法名称
* @param {*} returnData 返回值
* @return {bool} 校验结果
*/
const
checkReturnType
=
function
(
methodName
,
returnData
)
{
let
output
;
if
(
getType
(
methodName
)
==
'
Array
'
)
{
output
=
types
[
methods
[
methodName
[
0
]].
input
[
methodName
[
1
]]].
output
;
}
else
{
output
=
methods
[
methodName
].
output
;
}
// todo output 为什么可以是数组
// if (output instanceof Array) {
// output.forEach(type => {
// //todo 而且是要有一个校验不符合就check失败? 应该是有一个校验通过就可以吧
// checkType(returnData, type,[])
// });
// }
let
errList
=
checkType
(
returnData
,
output
,
[]);
if
(
errList
&&
errList
.
length
>
0
)
{
__CML_ERROR__
(
`
校验位置: 方法
${
methodName
}
返回值
错误信息:
${
errList
.
join
(
'
\n
'
)}
`
)
}
};
/**
* 创建warpper
*
* @param {string} funcName 方法名称
* @param {Function} originFunc 原有方法
* @return {Function} 包裹后的方法
*/
const
createWarpper
=
function
(
funcName
,
originFunc
)
{
return
function
()
{
const
argValues
=
Array
.
prototype
.
slice
.
call
(
arguments
)
.
map
(
function
(
arg
,
index
)
{
// 对传入的方法要做特殊的处理,这个是传入的callback,对callback函数再做包装
if
(
getType
(
arg
)
==
'
Function
'
)
{
return
createWarpper
([
funcName
,
index
],
arg
);
}
return
arg
;
});
checkArgsType
(
funcName
,
argValues
);
const
result
=
originFunc
.
apply
(
this
,
argValues
);
checkReturnType
(
funcName
,
result
)
return
result
;
}
};
// 获取所有方法
const
keys
=
Object
.
keys
(
methods
);
// 处理包装方法
keys
.
forEach
(
key
=>
{
const
originFunc
=
obj
[
key
];
if
(
!
originFunc
)
{
__CML_ERROR__
(
'
method [
'
+
key
+
'
] not found!
'
);
return
;
}
if
(
obj
.
hasOwnProperty
(
key
))
{
obj
[
key
]
=
createWarpper
(
key
,
originFunc
);
}
else
{
Object
.
getPrototypeOf
(
obj
)[
key
]
=
createWarpper
(
key
,
originFunc
);
}
});
return
obj
;
};
packages/mvvm-interface-parser/test/checkWrapper.test.js
0 → 100644
浏览文件 @
acbdc105
const
_
=
require
(
'
../runtime/checkWrapper.js
'
);
const
expect
=
require
(
'
chai
'
).
expect
;
var
__INTERFACE__FILEPATH
=
"
node_modules/chameleon-api/src/interfaces/showToast/index.interface
"
;
var
__CML_ERROR__
=
function
throwError
(
content
)
{
throw
new
Error
(
"
\
u6587
\
u4EF6
\
u4F4D
\
u7F6E:
"
+
__INTERFACE__FILEPATH
+
"
\n
"
+
content
);
};
var
__enableTypes__
=
""
;
var
__CHECK__DEFINES__
=
{
"
types
"
:
{
"
toastOpt
"
:
{
"
message
"
:
"
String
"
,
"
duration
"
:
"
Number
"
,
"
date
"
:
"
Null
"
}
},
"
interfaces
"
:
{
"
uiInterface
"
:
{
"
showToast
"
:
{
"
input
"
:
[
"
toastOpt
"
],
"
output
"
:
"
Undefined
"
}
}
},
"
classes
"
:
{
"
Method
"
:
[
"
uiInterface
"
]
}
};
function
Method
()
{
}
Method
.
prototype
.
showToast
=
function
({
message
,
duration
})
{
}
var
obj
=
_
(
new
Method
(),
__CML_ERROR__
,
__enableTypes__
,
__CHECK__DEFINES__
);
describe
(
'
mvvm-interface-parser/checkWrapper
'
,
function
()
{
it
(
'
定义了String类型的参数,传入的却是Number
'
,
function
()
{
obj
.
showToast
({
message
:
'
22
'
,
duration
:
123
,
"
date
"
:
null
})
try
{
obj
.
showToast
({
message
:
23
,
duration
:
123
,
"
date
"
:
null
})
}
catch
(
e
)
{
expect
(
!!~
e
.
message
.
indexOf
(
'
错误信息: 定义了String类型的参数,传入的却是Number
'
)).
to
.
equal
(
true
)
}
})
it
(
'
定义了String类型的参数,传入的却是Null
'
,
function
()
{
try
{
obj
.
showToast
({
message
:
null
,
duration
:
123
,
"
date
"
:
null
})
}
catch
(
e
)
{
expect
(
!!~
e
.
message
.
indexOf
(
'
定义了String类型的参数,传入的却是Null
'
)).
to
.
equal
(
true
)
}
})
})
packages/mvvm-pack/cmlNode.js
浏览文件 @
acbdc105
...
...
@@ -7,7 +7,8 @@ class CMLNode {
this
.
dependencies
=
[];
// 该节点的直接依赖 app.cml依赖pages.cml pages.cml依赖components.cml js依赖js
this
.
childrens
=
[];
// 子模块 cml文件才有子模块
this
.
parent
;
// 父模块 cml文件中的子模块才有
this
.
source
;
// 模块源代码
this
.
originSource
;
// 模块源代码
this
.
source
;
// 模块标准编译后代码
this
.
convert
;
// 源代码的格式化形式
this
.
output
;
// 模块输出 各种过程操作该字段
this
.
identifier
;
// 节点唯一标识
...
...
packages/mvvm-pack/compiler.js
浏览文件 @
acbdc105
...
...
@@ -189,6 +189,10 @@ class Compiler {
options
.
source
=
module
.
_source
&&
module
.
_source
.
_value
;
}
if
(
module
.
_cmlOriginSource
!==
undefined
)
{
options
.
originSource
=
module
.
_cmlOriginSource
;
}
if
(
options
.
moduleType
===
'
template
'
)
{
options
.
convert
=
cmlparse
(
options
.
source
);
options
.
extra
=
{
...
...
packages/mvvm-pack/lib/amdbootstrap.module.js
浏览文件 @
acbdc105
...
...
@@ -31,7 +31,7 @@
var
ret
=
(
typeof
factory
==
'
function
'
)
?
factory
.
apply
(
mod
,
[
cmlrequire
,
mod
.
exports
,
mod
])
:
factory
;
debugger
if
(
ret
)
{
mod
.
exports
=
ret
;
}
...
...
packages/mvvm-pack/package.json
浏览文件 @
acbdc105
...
...
@@ -5,7 +5,8 @@
"main"
:
"index.js"
,
"scripts"
:
{
"cover"
:
"istanbul cover --report lcov node_modules/mocha/bin/_mocha -- -R spec --recursive"
,
"test"
:
"mocha --recursive --reporter spec"
"test"
:
"mocha --recursive --reporter spec"
,
"test-brk"
:
"node --inspect-brk node_modules/mocha/bin/mocha --recursive --reporter spec"
},
"author"
:
"Chameleon-Team"
,
"license"
:
"Apache"
,
...
...
packages/mvvm-pack/test/cmlNode.test.js
0 → 100644
浏览文件 @
acbdc105
var
CMLNode
=
require
(
'
../cmlNode.js
'
)
const
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
cmlNode
'
,
function
()
{
it
(
'
constructor
'
,
function
()
{
var
cmlNode
=
new
CMLNode
({
ext
:
'
.cml
'
,
realPath
:
'
realPath
'
,
// 文件物理地址
nodeType
:
'
nodeType
'
,
// app/page/component/module // 节点类型 app/page/component 其他的为module cml文件中的每一个部分也是一个Node节点
moduleType
:
'
moduleType
'
,
// template/style/script/json/asset
dependencies
:
[
'
dependencies
'
],
// 该节点的直接依赖 app.cml依赖pages.cml pages.cml依赖components.cml js依赖js
childrens
:
[
'
dependencies
'
],
// 子模块 cml文件才有子模块
parent
:
'
parent
'
,
// 父模块 cml文件中的子模块才有
source
:
'
source
'
,
// 模块源代码
convert
:
'
convert
'
,
// 源代码的格式化形式
output
:
'
output
'
,
// 模块输出 各种过程操作该字段
identifier
:
'
identifier
'
,
// 节点唯一标识
modId
:
'
modId
'
,
// 模块化的id requirejs
extra
:
'
extra
'
// 节点的额外信息
})
expect
(
cmlNode
.
ext
).
to
.
be
.
equal
(
'
.cml
'
)
expect
(
cmlNode
.
realPath
).
to
.
be
.
equal
(
'
realPath
'
)
})
})
packages/mvvm-pack/test/lib/amd.test.js
0 → 100644
浏览文件 @
acbdc105
let
_
=
require
(
'
../../lib/amd.js
'
);
const
fs
=
require
(
'
fs
'
);
const
path
=
require
(
'
path
'
);
const
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
amd
'
,
function
()
{
it
(
'
amdWrapModule not has cmldefine
'
,
function
()
{
let
code
=
'
sdfsdfsdfsdfd
'
let
result
=
_
.
amdWrapModule
({
content
:
code
,
modId
:
'
123
'
})
expect
(
result
).
to
.
be
.
equal
(
'
\n
cmldefine(
\'
123
\'
, function(require, exports, module) {
\n
sdfsdfsdfsdfd
\n
})
'
)
})
it
(
'
amdWrapModule has cmldefine
'
,
function
()
{
let
code
=
'
\n
cmldefine(
\'
123
\'
, function(require, exports, module) {
\n
sdfsdfsdfsdfd
\n
})
'
;
let
result
=
_
.
amdWrapModule
({
content
:
code
,
modId
:
'
123
'
})
expect
(
result
).
to
.
be
.
equal
(
code
)
})
it
(
'
getModuleBootstrap
'
,
function
()
{
let
amdCode
=
fs
.
readFileSync
(
path
.
join
(
__dirname
,
'
../../lib/amdbootstrap.module.js
'
),
{
encoding
:
'
utf8
'
})
let
result
=
_
.
getModuleBootstrap
()
expect
(
result
).
to
.
be
.
equal
(
amdCode
)
})
it
(
'
getGlobalBootstrap
'
,
function
()
{
let
result
=
_
.
getGlobalBootstrap
(
'
global
'
)
expect
(
!!~
result
.
indexOf
(
'
(global)
'
)).
to
.
be
.
equal
(
true
)
})
})
packages/mvvm-pack/test/lib/amdbootstrap.global.test.js
0 → 100644
浏览文件 @
acbdc105
let
fs
=
require
(
'
fs
'
);
let
path
=
require
(
'
path
'
);
let
code
=
fs
.
readFileSync
(
path
.
join
(
__dirname
,
'
../../lib/amdbootstrap.global.js
'
),
{
encoding
:
'
utf8
'
})
const
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
amdbootstrap.global.js
'
,
function
()
{
it
(
'
global cmldefine
'
,
function
()
{
code
=
`
${
code
.
replace
(
'
$GLOBAL
'
,
'
global
'
)}
`
eval
(
code
)
global
.
cmldefine
(
'
name
'
,
function
(
require
,
exports
,
module
)
{
global
.
unittest
=
'
123
'
;
})
global
.
cmlrequire
(
'
name
'
);
expect
(
global
.
unittest
).
to
.
be
.
equal
(
'
123
'
);
})
})
packages/mvvm-pack/test/lib/amdbootstrap.module.test.js
0 → 100644
浏览文件 @
acbdc105
let
amd
=
require
(
'
../../lib/amdbootstrap.module.js
'
)
const
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
amdbootstrap.moudle.js
'
,
function
()
{
it
(
'
module cmldefine
'
,
function
()
{
amd
.
cmldefine
(
'
name
'
,
function
(
require
,
exports
,
module
)
{
global
.
unittest
=
'
123
'
;
})
amd
.
cmlrequire
(
'
name
'
);
amd
.
cmlrequire
(
'
name
'
);
expect
(
global
.
unittest
).
to
.
be
.
equal
(
'
123
'
);
})
it
(
'
module not find
'
,
function
()
{
amd
.
cmldefine
(
'
name
'
,
function
(
require
,
exports
,
module
)
{
global
.
unittest
=
'
123
'
;
})
try
{
amd
.
cmlrequire
(
'
name2
'
);
}
catch
(
e
)
{
expect
(
!!~
e
.
message
.
indexOf
(
'
[ModJS] Cannot find module
'
)).
to
.
be
.
equal
(
true
);
}
})
it
(
'
module has return
'
,
function
()
{
amd
.
cmldefine
(
'
name3
'
,
function
(
require
,
exports
,
module
)
{
return
'
has return
'
;
})
var
value
=
amd
.
cmlrequire
(
'
name3
'
);
expect
(
!!~
value
.
indexOf
(
'
has return
'
)).
to
.
be
.
equal
(
true
);
})
})
packages/mvvm-pack/test/amdwrapper.test.js
→
packages/mvvm-pack/test/
lib/
amdwrapper.test.js
浏览文件 @
acbdc105
let
wrapper
=
require
(
'
../lib/amdwrapper
'
);
let
wrapper
=
require
(
'
../
../
lib/amdwrapper
'
);
const
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
amdwrapper
'
,
function
()
{
...
...
packages/mvvm-pack/test/lib/replaceJsModId.test.js
0 → 100644
浏览文件 @
acbdc105
let
_
=
require
(
'
../../lib/replaceJsModId.js
'
);
const
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
replaceJsModId.js
'
,
function
()
{
it
(
'
replaceJsModId
'
,
function
()
{
let
code
=
`
import a from '../a.js';
var b = require('../b.js');
require('../c.js');
`
var
target
=
{
dependencies
:
[
{
request
:
'
../a.js
'
,
module
:
{
request
:
'
../a.js
'
,
id
:
'
a
'
}
},
{
request
:
'
../b.js
'
,
module
:
{
request
:
'
../b.js
'
,
id
:
'
b
'
}
},
{
request
:
'
../c.js
'
,
module
:
{
request
:
'
../c.js
'
,
id
:
'
c
'
}
}
]
}
let
result
=
_
.
replaceJsModId
(
code
,
target
);
console
.
log
(
result
)
expect
(
!!~
result
.
indexOf
(
'
var b = require("b")
'
)).
to
.
be
.
equal
(
true
);
expect
(
!!~
result
.
indexOf
(
'
import a from "a";
'
)).
to
.
be
.
equal
(
true
);
expect
(
!!~
result
.
indexOf
(
'
require("c");
'
)).
to
.
be
.
equal
(
true
);
})
it
(
'
no modId
'
,
function
()
{
let
code
=
`
import a from '../a.js';
var b = require('../b.js');
require('../c.js');
`
var
target
=
{
dependencies
:
[
{
request
:
'
../a.js
'
,
module
:
{
request
:
'
../a.js
'
,
id
:
'
a
'
}
},
{
request
:
'
../b.js
'
,
module
:
{
request
:
'
../b.js
'
,
id
:
'
b
'
}
}
]
}
try
{
_
.
replaceJsModId
(
code
,
target
);
}
catch
(
e
)
{
}
})
})
packages/mvvm-template-parser/test/index.test.js
0 → 100644
浏览文件 @
acbdc105
var
_
=
require
(
'
../index.js
'
);
var
expect
=
require
(
'
chai
'
).
expect
;
describe
(
'
mvvm-template-parser
'
,
function
()
{
it
(
'
cmlparse
'
,
function
()
{
let
content
=
`
<view c-if="show">
<view c-bind:click="click"></view>
<view name="{{name}}"></view>
<view c-for="list"></view>
</view>
`
let
result
=
_
.
cmlparse
(
content
);
expect
(
typeof
result
).
to
.
be
.
equal
(
'
object
'
)
});
it
(
'
postParseUnicode
'
,
function
()
{
let
content
=
`\u4f60\u597d`
;
let
result
=
_
.
postParseUnicode
(
content
);
expect
(
result
).
to
.
be
.
equal
(
'
你好
'
)
});
it
(
'
generator
'
,
function
()
{
let
content
=
`
<view c-if="show">
<view c-bind:click="click"></view>
<view name="{{name}}"></view>
<view c-for="list"></view>
</view>
`
let
result
=
_
.
cmlparse
(
content
);
let
code
=
_
.
generator
(
result
).
code
;
console
.
log
(
code
)
expect
(
code
).
to
.
be
.
equal
(
'
<view c-if="show">
\n
<view c-bind:click="click"></view>
\n
<view name="{{name}}"></view>
\n
<view c-for="list"></view>
\n
</view>
'
)
});
})
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录