diff --git a/packages/chameleon-tool/configs/getCommonConfig.js b/packages/chameleon-tool/configs/getCommonConfig.js
index e0ad61e2c88fc16385d079dea0844ff134b2c682..c7959597e5d0378eb0ddcfc54b8477b1ae266971 100644
--- a/packages/chameleon-tool/configs/getCommonConfig.js
+++ b/packages/chameleon-tool/configs/getCommonConfig.js
@@ -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)(\?.*)?$/,
diff --git a/packages/chameleon-tool/configs/mvvm/getExtendConfig.js b/packages/chameleon-tool/configs/mvvm/getExtendConfig.js
index e3bbe06802b7643937b9fec1f33bfe12ab38bc89..b6984c8a197932c9203bf2c0177f352fa16be8b0 100644
--- a/packages/chameleon-tool/configs/mvvm/getExtendConfig.js
+++ b/packages/chameleon-tool/configs/mvvm/getExtendConfig.js
@@ -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用于处理特有文件后缀
diff --git a/packages/chameleon-tool/configs/mvvm/originSourceLoader.js b/packages/chameleon-tool/configs/mvvm/originSourceLoader.js
new file mode 100644
index 0000000000000000000000000000000000000000..d8de013b7ddf7b1ebd578d4628634b4b07e599a7
--- /dev/null
+++ b/packages/chameleon-tool/configs/mvvm/originSourceLoader.js
@@ -0,0 +1,7 @@
+/**
+ * js 模块获取节点源代码,在interface-loader处理后 babel-loader前
+ */
+module.exports = function (output) {
+ this._module._cmlOriginSource = output;
+ return output;
+}
diff --git a/packages/chameleon-tool/configs/mvvm/styleWrapLoader.js b/packages/chameleon-tool/configs/mvvm/styleWrapLoader.js
deleted file mode 100644
index 2f3554866cc0cdf83ad2afeb4400aac26800a9e9..0000000000000000000000000000000000000000
--- a/packages/chameleon-tool/configs/mvvm/styleWrapLoader.js
+++ /dev/null
@@ -1,33 +0,0 @@
-
-/** 为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
- }
-}
-
diff --git a/packages/chameleon-tool/configs/mvvm/utils.js b/packages/chameleon-tool/configs/mvvm/utils.js
deleted file mode 100644
index 8b137891791fe96927ad78e64b0aad7bded08bdc..0000000000000000000000000000000000000000
--- a/packages/chameleon-tool/configs/mvvm/utils.js
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/interface-loader/src/index.js b/packages/interface-loader/src/index.js
index f69acc9aea402f3a708c22d69db2ac78487e805c..c2906bc4ae184c6f7f0dc405ed2b7a1a26f17983 100644
--- a/packages/interface-loader/src/index.js
+++ b/packages/interface-loader/src/index.js
@@ -1,19 +1,12 @@
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 => {
diff --git a/packages/mvvm-interface-parser/lib/check.js b/packages/mvvm-interface-parser/lib/check.js
index 70bffe51e94b4f85fbcc50e8cc6caf43fadea973..2dfc3a61f658bf23ef09abde1ee9f6e9f5730d57 100644
--- a/packages/mvvm-interface-parser/lib/check.js
+++ b/packages/mvvm-interface-parser/lib/check.js
@@ -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}"
diff --git a/packages/mvvm-interface-parser/runtime/checkWrapper.js b/packages/mvvm-interface-parser/runtime/checkWrapper.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f8dea505f6d8fc833e668ba533b1b43425c4cb6
--- /dev/null
+++ b/packages/mvvm-interface-parser/runtime/checkWrapper.js
@@ -0,0 +1,296 @@
+/**
+* 对象包裹器
+*运行时的错误信息,根据端传入不同的方法,
+* @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;
+};
diff --git a/packages/mvvm-interface-parser/test/checkWrapper.test.js b/packages/mvvm-interface-parser/test/checkWrapper.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..621945e3678eede0313f4c62247798366de45f6f
--- /dev/null
+++ b/packages/mvvm-interface-parser/test/checkWrapper.test.js
@@ -0,0 +1,73 @@
+
+
+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)
+ }
+ })
+
+})
+
diff --git a/packages/mvvm-pack/cmlNode.js b/packages/mvvm-pack/cmlNode.js
index b635f77d7fec90c66f0d1ae95fb68a536c10c482..1a1edb0b2cec37dbc5c886185ae23dd93f48915f 100644
--- a/packages/mvvm-pack/cmlNode.js
+++ b/packages/mvvm-pack/cmlNode.js
@@ -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; // 节点唯一标识
diff --git a/packages/mvvm-pack/compiler.js b/packages/mvvm-pack/compiler.js
index f4118b2db834d79019ce62e570f402c6b892657c..8c952929c1d818557b8daf31311fe37c2d380d11 100644
--- a/packages/mvvm-pack/compiler.js
+++ b/packages/mvvm-pack/compiler.js
@@ -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 = {
diff --git a/packages/mvvm-pack/lib/amdbootstrap.module.js b/packages/mvvm-pack/lib/amdbootstrap.module.js
index 2feab89d80dcdb057b9bfecc8f2a6f46aaedf821..77142122c2ccd9a1076222b4cb0d63b8686ad217 100644
--- a/packages/mvvm-pack/lib/amdbootstrap.module.js
+++ b/packages/mvvm-pack/lib/amdbootstrap.module.js
@@ -31,7 +31,7 @@
var ret = (typeof factory == 'function')
? factory.apply(mod, [cmlrequire, mod.exports, mod])
: factory;
-
+ debugger
if (ret) {
mod.exports = ret;
}
diff --git a/packages/mvvm-pack/package.json b/packages/mvvm-pack/package.json
index b3d86f9af89dfce2ceb5d1a34397b3cde276180e..c344d0842e08985d02408740db23086a06a8d0db 100644
--- a/packages/mvvm-pack/package.json
+++ b/packages/mvvm-pack/package.json
@@ -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",
diff --git a/packages/mvvm-pack/test/cmlNode.test.js b/packages/mvvm-pack/test/cmlNode.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..557bcc4e1d0214d5107f6920a2cf1d8efc03720a
--- /dev/null
+++ b/packages/mvvm-pack/test/cmlNode.test.js
@@ -0,0 +1,27 @@
+
+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')
+ })
+
+})
diff --git a/packages/mvvm-pack/test/lib/amd.test.js b/packages/mvvm-pack/test/lib/amd.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ccf459e0a4b5d0f74bc98e9fa919c1cb7f78089
--- /dev/null
+++ b/packages/mvvm-pack/test/lib/amd.test.js
@@ -0,0 +1,32 @@
+
+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('\ncmldefine(\'123\', function(require, exports, module) {\n sdfsdfsdfsdfd\n})')
+ })
+ it('amdWrapModule has cmldefine', function() {
+ let code = '\ncmldefine(\'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)
+ })
+})
+
diff --git a/packages/mvvm-pack/test/lib/amdbootstrap.global.test.js b/packages/mvvm-pack/test/lib/amdbootstrap.global.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..921252aa9a6d9bbfdbb255cd5720f2a0e19f8a61
--- /dev/null
+++ b/packages/mvvm-pack/test/lib/amdbootstrap.global.test.js
@@ -0,0 +1,21 @@
+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');
+
+ })
+})
+
diff --git a/packages/mvvm-pack/test/lib/amdbootstrap.module.test.js b/packages/mvvm-pack/test/lib/amdbootstrap.module.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6ea294293a556232ca40c3dd2b0d9df68aa43c9
--- /dev/null
+++ b/packages/mvvm-pack/test/lib/amdbootstrap.module.test.js
@@ -0,0 +1,39 @@
+
+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);
+ })
+})
+
diff --git a/packages/mvvm-pack/test/amdwrapper.test.js b/packages/mvvm-pack/test/lib/amdwrapper.test.js
similarity index 92%
rename from packages/mvvm-pack/test/amdwrapper.test.js
rename to packages/mvvm-pack/test/lib/amdwrapper.test.js
index 23c97740170cc22f3d835e993bc4e92b56a0b1c5..879d18d1e42d6595395977b7e48b8c343eb3a6a2 100644
--- a/packages/mvvm-pack/test/amdwrapper.test.js
+++ b/packages/mvvm-pack/test/lib/amdwrapper.test.js
@@ -1,4 +1,4 @@
-let wrapper = require('../lib/amdwrapper');
+let wrapper = require('../../lib/amdwrapper');
const expect = require('chai').expect;
describe('amdwrapper', function() {
diff --git a/packages/mvvm-pack/test/lib/replaceJsModId.test.js b/packages/mvvm-pack/test/lib/replaceJsModId.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..521ab34bf95b87d8264471b00193137c7afe0c4c
--- /dev/null
+++ b/packages/mvvm-pack/test/lib/replaceJsModId.test.js
@@ -0,0 +1,75 @@
+
+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) {
+ }
+ })
+})
+
diff --git a/packages/mvvm-template-parser/test/index.test.js b/packages/mvvm-template-parser/test/index.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9f5365fa63b2127c1d3d2995e378a72d8517a592
--- /dev/null
+++ b/packages/mvvm-template-parser/test/index.test.js
@@ -0,0 +1,37 @@
+var _ = require('../index.js');
+var expect = require('chai').expect;
+
+describe('mvvm-template-parser', function() {
+ it('cmlparse', function() {
+ let content = `
+
+
+
+
+
+ `
+ 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 = `
+
+
+
+
+
+ `
+ let result = _.cmlparse(content);
+ let code = _.generator(result).code;
+ console.log(code)
+ expect(code).to.be.equal('\n \n \n \n ')
+ });
+})
\ No newline at end of file