未验证 提交 acbdc105 编写于 作者: B beatles-chameleon 提交者: GitHub

Merge pull request #179 from didi/0.4.x-dev-yyl

0.4.x dev yyl
......@@ -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)(\?.*)?$/,
......
......@@ -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用于处理特有文件后缀
......
/**
* js 模块获取节点源代码,在interface-loader处理后 babel-loader前
*/
module.exports = function (output) {
this._module._cmlOriginSource = output;
return output;
}
/** 为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
}
}
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 => {
......
......@@ -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}"
......
/**
* 对象包裹器
*运行时的错误信息,根据端传入不同的方法,
* @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;
};
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)
}
})
})
......@@ -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; // 节点唯一标识
......
......@@ -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 = {
......
......@@ -31,7 +31,7 @@
var ret = (typeof factory == 'function')
? factory.apply(mod, [cmlrequire, mod.exports, mod])
: factory;
debugger
if (ret) {
mod.exports = ret;
}
......
......@@ -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",
......
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')
})
})
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)
})
})
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');
})
})
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);
})
})
let wrapper = require('../lib/amdwrapper');
let wrapper = require('../../lib/amdwrapper');
const expect = require('chai').expect;
describe('amdwrapper', function() {
......
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) {
}
})
})
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.
先完成此消息的编辑!
想要评论请 注册