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

V0.2.x bugfix (#111)

* check

* update

* api update

* component is modify

* modify component-attr-check

* 添加 component is 测试用例

* add app entrence test

* add cml-htmllinter test case
上级 a81b8c0e
const list = [{
name: 'app',
allowAttrs: {
vars: ['store', 'routerConfig'],
methods: [],
props: [{
name: 'store',
required: true
}, {
name: 'routerConfig',
required: true
}],
events: []
}
}, {
name: 'component',
allowAttrs: {
vars: ['is', 'shrinkcomponents'],
methods: [],
props: [{
name: 'is',
required: true
}, {
name: 'shrinkcomponents',
required: false
}],
events: []
}
}];
module.exports = list;
......@@ -2,8 +2,6 @@
* tags: Technically, it only holds tags that are not a html tag.
*/
module.exports = {
// attrs: ['v-if','v-else','v-bind','v-cloak','v-for','v-html','v-model','v-on','v-once','v-pre','v-show','v-text'],
attrs: ['v-if', 'v-else', 'v-else-if', 'v-for', 'v-on', 'v-bind', 'v-html', 'v-show', 'v-model', 'v-pre', 'v-once', 'slot-scope', 'is'],
// tags: ['template','component','keep-alive','transition','transition-group']
attrs: ['v-if', 'v-else', 'v-else-if', 'v-for', 'v-on', 'v-bind', 'v-html', 'v-show', 'v-model', 'v-pre', 'v-once', 'slot-scope'],
tags: ['template', 'view', 'text', 'block', 'scroller', 'list', 'cell', 'image', 'switch', 'video', 'input', 'button', 'radio', 'checkbox', 'page', 'router-view', 'slot']
}
......@@ -4,6 +4,7 @@ const config = require('../config');
const whiteListConifg = require('../config/white-list');
const builtinComponents = require('../config/built-in-components');
const tagEmbedRules = require('../config/tag-embed-rules.json');
const fakeComps = require('../config/fakeComps');
const utils = require('../utils');
const linter = new htmllint.Linter();
......@@ -117,26 +118,12 @@ function getLintOptions(params) {
* A temporary solution for application entrance file app.cml
* @param {Object} options lint options
*/
function addFakeAppComp(options) {
function addFakeComp(options, comp) {
if (options['component-allow-attr']) {
options['component-allow-attr'].app = {
vars: ['store', 'routerConfig'],
methods: [],
props: [{
name: 'store',
required: true
}, {
name: 'routerConfig',
required: true
}],
events: []
};
options['component-allow-attr'][comp.name] = comp.allowAttrs;
}
}
function addFakeAppTag(options) {
if (options['tag-only-allowed-names']) {
options['tag-only-allowed-names'].push('app');
options['tag-only-allowed-names'].push(comp.name);
}
}
......@@ -188,10 +175,16 @@ module.exports = (part, jsonAst) => {
})}
});
// adding fake comps
const allowedFakeComps = ['component'];
if (isAppEntranceFile(part.file)) {
addFakeAppTag(lintOptions);
addFakeAppComp(lintOptions);
allowedFakeComps.push('app');
}
fakeComps && fakeComps.forEach((comp) => {
if (~allowedFakeComps.indexOf(comp.name)) {
addFakeComp(lintOptions, comp);
}
});
lintResults = await htmllint(part.rawContent, lintOptions);
......
......@@ -6,7 +6,8 @@ module.exports = [{
rawContent: "<template lang='web'></template>",
params: {
lang: ''
}
},
file: '/src/app.cml'
},
jsonAst: {}
},
......
module.exports = [{
desc: 'should pass component is attribute check',
input: {
part: {
line: 0,
rawContent: ["<template lang='vue",
"<component :is='currentComp' class='comp-normal' :class='comp-directive'></button>",
'</template>'].join('\n'),
params: {
lang: ''
}
},
jsonAst: {}
},
output: {
start: 0,
messages: []
}
}];
......@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"chameleon-api": {
"version": "0.3.0-alpha.4",
"resolved": "https://registry.npmjs.org/chameleon-api/-/chameleon-api-0.3.0-alpha.4.tgz",
"integrity": "sha512-NxKQBJpN84t9XRgOGCcvjfjj4QIzZNECT7wX0PM1ObK4x/vPesJ+4vRxQrss8xJvYjFvve7GncTyM1Tm1RxNHw==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/chameleon-api/-/chameleon-api-0.4.0.tgz",
"integrity": "sha512-21Qc7wSE62uyMsWaK/g1HFdAkobYuusufeojfptt56y4v4epu1O6LKLMsdCV2Gi6x0uIe1gYskvCkxmPdh2Bvw==",
"requires": {
"chameleon-bridge": "0.1.0",
"child_process": "1.0.2",
......@@ -28,9 +28,9 @@
"integrity": "sha512-5IFZPamHYErbMYPD/H+RT5GAmxDqDZ0YlkBAbDGIDm82WFEFlpp7MnDclb1ZjJ2/txz3WmUOQQq/ZvOrVqACJg=="
},
"chameleon-runtime": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/chameleon-runtime/-/chameleon-runtime-0.1.0.tgz",
"integrity": "sha512-bfAvgQb3cYsNLcYkLDLbkXz88g6Pr8bC8BpAhJyibbSBfMK++GnoZxB9Xq+OYyFHpJ6VP2Jn+f6S6lgFve4brw==",
"version": "0.2.0-alpha.0",
"resolved": "https://registry.npmjs.org/chameleon-runtime/-/chameleon-runtime-0.2.0-alpha.0.tgz",
"integrity": "sha512-4J8kT+9nqFpPuk+GJawKNDXcjpP4nEOvn7Jp8kbxdZi10dBHdovbX/CncSBuoyL3D1LttVq7ICjHlc9avYMuIQ==",
"requires": {
"mobx": "3.6.1"
}
......@@ -50,9 +50,9 @@
}
},
"chameleon-ui-builtin": {
"version": "0.0.7-alpha",
"resolved": "https://registry.npmjs.org/chameleon-ui-builtin/-/chameleon-ui-builtin-0.0.7-alpha.tgz",
"integrity": "sha512-k1FTI1GaGUVBhF3u5vBBZ01mOopi855emBcjkAR123VxOh1ZHh8nxlteDKADT7mTLIinyMsOiSOEO27OcFJbtA==",
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/chameleon-ui-builtin/-/chameleon-ui-builtin-0.1.2.tgz",
"integrity": "sha512-Oiqss1kq/12mzgJ9TkPtoBjfib91TfNtJ5e6w8vCgiZ2FtPHFSD00zH0nu7cHdTDDwDdwOhoE7ryWWYqVr4oqw==",
"requires": {
"chameleon-scroll": "0.0.3"
}
......@@ -68,9 +68,9 @@
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
"cml-ui": {
"version": "0.0.7-alpha",
"resolved": "https://registry.npmjs.org/cml-ui/-/cml-ui-0.0.7-alpha.tgz",
"integrity": "sha512-/O2GrK40igiwelIkfUCYuZQ1bzMeBilAaHFPdxfeF+BneJBH7ARgHhZISwTs8j537pnGYf8svDWUg8iFIZX7pA==",
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/cml-ui/-/cml-ui-0.1.3.tgz",
"integrity": "sha512-6XzWbiUwqsoB829gUXCKDS5EjcxCX4cZeBhZnZJrgaDP2ygGjZSp3tnWsgskUa2y78CWuPzMh/1+4TL0gm+nRQ==",
"requires": {
"classnames": "2.2.6"
}
......
......@@ -7,11 +7,11 @@
"scripts": {},
"license": "MIT",
"dependencies": {
"chameleon-api": "^0.3.0-alpha.4",
"chameleon-api": "^0.4.0",
"chameleon-bridge": "^0.1.1-alpha.2",
"chameleon-runtime": "^0.1.0",
"chameleon-runtime": "^0.2.0-alpha.0",
"chameleon-store": "0.0.3",
"chameleon-ui-builtin": "0.0.7-alpha",
"cml-ui": "0.0.7-alpha"
"chameleon-ui-builtin": "^0.1.2",
"cml-ui": "^0.1.3"
}
}
......@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"chameleon-api": {
"version": "0.3.0-alpha.4",
"resolved": "https://registry.npmjs.org/chameleon-api/-/chameleon-api-0.3.0-alpha.4.tgz",
"integrity": "sha512-NxKQBJpN84t9XRgOGCcvjfjj4QIzZNECT7wX0PM1ObK4x/vPesJ+4vRxQrss8xJvYjFvve7GncTyM1Tm1RxNHw==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/chameleon-api/-/chameleon-api-0.4.0.tgz",
"integrity": "sha512-21Qc7wSE62uyMsWaK/g1HFdAkobYuusufeojfptt56y4v4epu1O6LKLMsdCV2Gi6x0uIe1gYskvCkxmPdh2Bvw==",
"requires": {
"chameleon-bridge": "0.1.0",
"child_process": "1.0.2",
......@@ -28,9 +28,9 @@
"integrity": "sha512-5IFZPamHYErbMYPD/H+RT5GAmxDqDZ0YlkBAbDGIDm82WFEFlpp7MnDclb1ZjJ2/txz3WmUOQQq/ZvOrVqACJg=="
},
"chameleon-runtime": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/chameleon-runtime/-/chameleon-runtime-0.1.0.tgz",
"integrity": "sha512-bfAvgQb3cYsNLcYkLDLbkXz88g6Pr8bC8BpAhJyibbSBfMK++GnoZxB9Xq+OYyFHpJ6VP2Jn+f6S6lgFve4brw==",
"version": "0.2.0-alpha.0",
"resolved": "https://registry.npmjs.org/chameleon-runtime/-/chameleon-runtime-0.2.0-alpha.0.tgz",
"integrity": "sha512-4J8kT+9nqFpPuk+GJawKNDXcjpP4nEOvn7Jp8kbxdZi10dBHdovbX/CncSBuoyL3D1LttVq7ICjHlc9avYMuIQ==",
"requires": {
"mobx": "3.6.1"
}
......@@ -50,9 +50,9 @@
}
},
"chameleon-ui-builtin": {
"version": "0.0.7-alpha",
"resolved": "https://registry.npmjs.org/chameleon-ui-builtin/-/chameleon-ui-builtin-0.0.7-alpha.tgz",
"integrity": "sha512-k1FTI1GaGUVBhF3u5vBBZ01mOopi855emBcjkAR123VxOh1ZHh8nxlteDKADT7mTLIinyMsOiSOEO27OcFJbtA==",
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/chameleon-ui-builtin/-/chameleon-ui-builtin-0.1.2.tgz",
"integrity": "sha512-Oiqss1kq/12mzgJ9TkPtoBjfib91TfNtJ5e6w8vCgiZ2FtPHFSD00zH0nu7cHdTDDwDdwOhoE7ryWWYqVr4oqw==",
"requires": {
"chameleon-scroll": "0.0.3"
}
......@@ -68,9 +68,9 @@
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
"cml-ui": {
"version": "0.0.7-alpha",
"resolved": "https://registry.npmjs.org/cml-ui/-/cml-ui-0.0.7-alpha.tgz",
"integrity": "sha512-/O2GrK40igiwelIkfUCYuZQ1bzMeBilAaHFPdxfeF+BneJBH7ARgHhZISwTs8j537pnGYf8svDWUg8iFIZX7pA==",
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/cml-ui/-/cml-ui-0.1.3.tgz",
"integrity": "sha512-6XzWbiUwqsoB829gUXCKDS5EjcxCX4cZeBhZnZJrgaDP2ygGjZSp3tnWsgskUa2y78CWuPzMh/1+4TL0gm+nRQ==",
"requires": {
"classnames": "2.2.6"
}
......
......@@ -7,11 +7,11 @@
"scripts": {},
"license": "MIT",
"dependencies": {
"chameleon-api": "^0.3.0-alpha.4",
"chameleon-api": "^0.4.0",
"chameleon-bridge": "^0.1.1-alpha.2",
"chameleon-runtime": "^0.1.0",
"chameleon-runtime": "^0.2.0-alpha.0",
"chameleon-store": "0.0.3",
"chameleon-ui-builtin": "0.0.7-alpha",
"cml-ui": "0.0.7-alpha"
"chameleon-ui-builtin": "^0.1.2",
"cml-ui": "^0.1.3"
}
}
......@@ -68,7 +68,7 @@ var chameleonConfig = {
wxAppId: ''
},
enableLinter: true,
enableGlobalCheck: false,
enableGlobalCheck: true,
globalCheckWhiteList: [ // 全局校验的白名单文件 后缀匹配
],
cmss: {
......
......@@ -48,26 +48,35 @@ module.exports.lint = function (element, opts) {
let requiredProps = matchComponent.props.filter((node) => node.required).map((node) => node.name);
let events = matchComponent.events.map((method) => method.name);
Object.entries(element.attribs).filter((attrib) => {
if (knife.isCommonAttr(attrib[0]) || knife.isCmlDirective(attrib[0])) {
return false;
}
Object.entries(element.attribs).filter((attrib) => {
// verify events
if (eventRegex && eventRegex.test(attrib[0])) {
let eventName = eventRegex.exec(attrib[0])[1];
if (knife.isCommonEvent(eventName)) {
return false;
}
return !~events.indexOf(eventName);
}
if (!eventRegex && events.indexOf(attrib[0]) > -1) {
return false;
}
if (propRegex && propRegex.test(attrib[0])) {
return !~propNames.indexOf(toCamelcase(propRegex.exec(attrib[0])[1]));
// verify normal attributes
let attribProp = attrib[0];
if (propRegex && propRegex.test(attribProp)) {
attribProp = propRegex.exec(attribProp)[1];
}
if (!propRegex && propNames.indexOf(toCamelcase(attrib[0])) > -1) {
if (knife.isCommonAttr(attribProp) || knife.isCmlDirective(attribProp)) {
return false;
}
if (!eventRegex && events.indexOf(attrib[0]) > -1) {
if (propNames.indexOf(toCamelcase(attribProp)) > -1) {
return false;
}
}
return true;
})
.forEach(attrib => {
......@@ -78,7 +87,14 @@ module.exports.lint = function (element, opts) {
});
if (requiredProps.length) {
let attrKeys = Object.keys(element.attribs);
let attrKeys = Object.keys(element.attribs);
attrKeys = attrKeys.map(attr => {
if (propRegex && propRegex.exec(attr)) {
return propRegex.exec(attr)[1];
} else {
return attr;
}
});
requiredProps.forEach((propName) => {
if (!~attrKeys.indexOf(toDash(propName))) {
issues.push(new Issue('E073', element.openLineCol, {
......
......@@ -10,7 +10,9 @@
],
"author": "Chameleon-Team",
"main": "lib/index.js",
"scripts": {},
"scripts": {
"test": "nyc ./node_modules/mocha/bin/mocha ./test/**/*.test.js --timeout=3000"
},
"mail": "ChameleonCore@didiglobal.com",
"license": "Apache",
"devDependencies": {
......
module.exports = [
{
desc: 'should pass component-attr-check',
input: '<template lang="cml"><component is="{{currentComp}}" style="comp"></component></template>',
opts: {
'component-event-regex': /(?:c-bind:|c-catch:)(\w+)/,
'component-prop-regex': false,
'component-allow-attr': [{
name: 'component',
allowAttrs: {
vars: ['is', 'shrinkcomponents'],
methods: [],
props: [{
name: 'is',
required: true
}, {
name: 'shrinkcomponents',
required: false
}],
events: []
}
}]
},
output: 0
},
{
desc: 'should not pass component-attr-check',
input: '<template lang="cml"><component shrinkcomponents="comp,comp1"></component></template>',
opts: {
'component-event-regex': /(?:c-bind:|c-catch:)(\w+)/,
'component-prop-regex': false,
'component-allow-attr': {
component:{
vars: ['is', 'shrinkcomponents'],
methods: [],
props: [{
name: 'is',
required: true
}, {
name: 'shrinkcomponents',
required: false
}],
events: []
}
}
},
output: 1
}
];
const check = require('./lib/check.js');
const chalk = require('chalk');
class WebpackCheckPlugin {
constructor(options) {
this.options = Object.assign({
constructor(options) {
this.options = Object.assign({
cmlType: '',
tokensMap: undefined,
whiteListFile: []
}, options);
}
}, options);
}
apply(compiler) {
const options = this.options;
if(compiler.hooks) {
apply(compiler) {
const options = this.options;
if (compiler.hooks) {
compiler.hooks.emit.tap('chameleon-plugin', checkModule);
} else {
compiler.plugin('emit', checkModule);
}
//check babel之后的每一个module
function checkModule(compilation, callback) {
// check babel之后的每一个module
function checkModule(compilation, callback) {
var type = options.cmlType;
compilation.modules.forEach(module=>{
//项目内的文件做校验
if(module.resource && module.resource.indexOf(cml.projectRoot) === 0) {
//白名单内的文件不做校验
compilation.modules.forEach(module => {
// 项目内的文件做校验
if (module.resource && module.resource.indexOf(cml.projectRoot) === 0) {
// 白名单内的文件不做校验
let whiteListFileLength = options.whiteListFile.length;
let inWhiteList = false;
for(let i = 0; i < whiteListFileLength; i++){
for (let i = 0; i < whiteListFileLength; i++) {
let item = options.whiteListFile[i];
if(Object.prototype.toString.call(item) === '[object RegExp]'){ //配置的是正则
if(item.test(module.resource)){
if (Object.prototype.toString.call(item) === '[object RegExp]') { // 配置的是正则
if (item.test(module.resource)) {
inWhiteList = true;
break
}
}
if(Object.prototype.toString.call(item) === '[object String]'){ //配置的是绝对路径
if(module.resource.endsWith(item)){
if (Object.prototype.toString.call(item) === '[object String]') { // 配置的是绝对路径
if (module.resource.endsWith(item)) {
inWhiteList = true;
break;
}
}
}
if(!inWhiteList) {
if (!inWhiteList) {
var source = module._source && module._source._value;
var source = module._source && module._source._value;
let sourceLine = source.split('\n');
try {
var tokens = check(source, options);
if(tokens && tokens.length) {
tokens.forEach(token=>{
cml.log.warn(`
if (tokens && tokens.length) {
tokens.forEach(token => {
throw new Error(chalk.red(`
不能在${type} 项目中使用全局变量【${token.name}
文件位置: ${module.resource}
具体代码: ${sourceLine[token.loc.line-1]}
`)
具体代码: ${sourceLine[token.loc.line - 1]}
`))
})
}
}
catch(e) {
} catch (e) {
console.log(e)
//babel parse入会有报错的情况
// babel parse入会有报错的情况
}
}
}
})
return callback()
}
}
}
}
//check 最终输出的assets文件
function checkAssets(compilation, callback) {
var type = options.cmlType;
Object.keys(compilation.assets).forEach(key=>{
var item = compilation.assets[key];
var source = item.source();
try {
var tokens = check(source, type);
if(tokens && tokens.length) {
tokens.forEach(token=>{
cml.log.warn(`
不能在${type} 项目中使用【${token.name}】全局变量,
文件: ${key}
位置: ${token.loc.line}行,${token.loc.column}
`)
})
}
}
catch(e) {
//babel parse入会有报错的情况
}
})
return callback()
}
module.exports = WebpackCheckPlugin;
......@@ -13,6 +13,7 @@
"@babel/parser": "7.1.0",
"babel-generator": "6.26.1",
"babel-traverse": "6.26.0",
"chalk": "^2.4.2",
"lodash.uniq": "4.5.0"
},
"devDependencies": {
......@@ -28,4 +29,4 @@
"license": "Apache",
"mail": "ChameleonCore@didiglobal.com",
"gitHead": "5ddcde4330774710f7646559446e008f7785ce00"
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册