chameleon-linter
Version:
cml规范校验工具
121 lines (104 loc) • 3.9 kB
JavaScript
const jsAstParser = require('./lib/js-ast-parser');
const templateAstParser = require('./lib/template-ast-parser');
const jsonAstParser = require('./lib/json-ast-parser');
const commonEvents = require('../../config/common-events.json');
class TemplateChecker {
/**
* constructor
* @param {Object} trees
* {
* templateAst: {},
* scriptAst: {},
* jsonAst: {}
* }
*/
constructor(filePath = '', lintedResult = {}) {
this._filePath = filePath;
this._platform = lintedResult.template.platform;
this._templateAst = lintedResult.template.ast;
this._scriptAst = lintedResult.script.ast;
this._jsonAst = lintedResult.json.obj;
this._parsedTemplateResults = '';
this._parsedScriptResults = '';
this._usingComponents = '';
this.parseAllParts();
}
parseAllParts() {
this._usingComponents = jsonAstParser.getUsingComponents(this._jsonAst, this._filePath);
this._parsedScriptResults = jsAstParser.getParseResults(this._scriptAst);
this._parsedTemplateResults = templateAstParser.getParseResults(this._templateAst, {
usingComponents: Object.keys(this._usingComponents),
platform: this._platform
});
}
checkCustomizedComponents() {
let issues = [];
let usingComponents = this._usingComponents;
let customizedComponets = this._parsedTemplateResults.customizedComponents;
customizedComponets.forEach((component) => {
Object.entries(component).forEach((compInfo) => {
let compName = compInfo[0];
if (usingComponents[compName] && usingComponents[compName].isCml) {
let { props, events } = component[compName];
let { props: usingProps, events: usingEvents } = usingComponents[compName];
usingProps = usingProps
.map((prop) => prop.name)
.join('|');
usingEvents = usingEvents
.map((event) => event.name)
.concat(commonEvents.events)
.join('|');
usingProps = `|${usingProps}|`;
usingEvents = `|${usingEvents}|`;
props.filter((prop) => usingProps.indexOf('|' + prop.name + '|') === -1).forEach((prop) => {
issues.push({
line: prop.pos[0],
column: prop.pos[1],
token: prop.rawName,
msg: `The property "${prop.rawName}" is not a property of component "${compName}" which path is: ${usingComponents[compName].path}`
});
});
events.filter((event) => usingEvents.indexOf('|' + event.name + '|') === -1).forEach((event) => {
issues.push({
line: event.pos[0],
column: event.pos[1],
token: event.name,
msg: `The event "${event.name}" is not defined in component "${compName}" which path is: ${usingComponents[compName].path}`
});
});
}
});
});
return issues;
}
checkTemplateAndScript() {
let jsAstResults = this._parsedScriptResults;
let templateAstResults = this._parsedTemplateResults;
let issues = [];
templateAstResults.methods.forEach(method => {
if (jsAstResults.methods.indexOf(method.name) === -1) {
issues.push({
line: method.pos[0],
column: method.pos[1],
token: method.name,
msg: `method: "${method.name}" is not defined.`
});
}
});
templateAstResults.vars.forEach((varItem) => {
if (jsAstResults.vars.indexOf(varItem.name) === -1) {
issues.push({
line: varItem.pos[0],
column: varItem.pos[1],
token: varItem.name,
msg: `variable: "${varItem.name}" is not defined.`
});
}
});
return issues;
}
check() {
return [...this.checkCustomizedComponents(), ...this.checkTemplateAndScript()];
}
}
module.exports = TemplateChecker;