optimize code based on comments

This commit is contained in:
Fei Chen 2019-11-26 19:00:58 +08:00
Родитель 8db88f8ebb
Коммит cd3bb6ea90
1 изменённых файлов: 130 добавлений и 108 удалений

Просмотреть файл

@ -5,6 +5,7 @@ const luParser = require('./../lufile/luParser');
const SectionOperator = require('./../lufile/sectionOperator');
const LUSectionTypes = require('./../utils/enums/lusectiontypes');
const DiagnosticSeverity = require('./../lufile/diagnostic').DiagnosticSeverity;
const NEWLINE = require('os').EOL;
module.exports = {
/**
@ -22,85 +23,11 @@ module.exports = {
const intentName = crossTrainConfigObj.intentName;
const verbose = crossTrainConfigObj.verbose;
let fileIdToLuResourceMap = new Map();
for (const luObject of luObjectArray) {
let luContent = luObject.content;
luContent = helpers.sanitizeNewLines(luContent);
if (luContent === undefined || luContent === '') {
continue;
}
// parse lu content to LUResource object
let fileIdToLuResourceMap = this.parseAndValidateLuContent(luObjectArray, verbose);
let luResource = luParser.parse(luContent);
if (luResource.Errors && luResource.Errors.length > 0) {
if (verbose) {
var warns = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.WARN));
if (warns.length > 0) {
process.stdout.write(warns.map(warn => warn.toString()).join('\n').concat('\n'));
}
}
var errors = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.ERROR));
if (errors.length > 0) {
throw (new exception(retCode.errorCode.INVALID_LINE, errors.map(error => error.toString()).join('\n')));
}
}
fileIdToLuResourceMap.set(luObject.id, luResource);
}
/*
resources is array of below object
{
id: a.lu
content: LUResource
children: [ {target: "b.lu", intent: "b"} , {target: "c.lu", intent: "c"}]
}
*/
let visitedChildren = new Set();
let resources = [];
let fileIdsFromInput = Array.from(fileIdToLuResourceMap.keys());
for (const fileId of fileIdsFromInput) {
let luResource = fileIdToLuResourceMap.get(fileId);
let resource = {
id: fileId,
content: luResource,
children: []
};
if (fileId in triggerRules) {
let intents = [];
for (const section of luResource.Sections) {
if (section.SectionType === LUSectionTypes.SIMPLEINTENTSECTION
|| section.SectionType === LUSectionTypes.NESTEDINTENTSECTION) {
intents.push(section);
}
}
const destLuFileToIntent = triggerRules[fileId];
for (const destLuFile of Object.keys(destLuFileToIntent)) {
if (fileIdsFromInput.includes(destLuFile)) {
const triggerIntentName = destLuFileToIntent[destLuFile];
if (intents.some(i => i.Name === triggerIntentName)) {
if (visitedChildren.has(destLuFile)) {
// validate loop in a tree or forest
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, dialog call loop detected for lu file ${destLuFile} when doing cross training`));
} else {
resource.children.push({
target: destLuFile,
intent: triggerIntentName
});
visitedChildren.add(destLuFile);
}
} else {
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, trigger intent '${triggerIntentName}' is not found in lu file: ${fileId}`));
}
}
}
}
resources.push(resource);
}
// contruct resource tree to build the father-children relationship among lu files
let resources = this.constructResoureTree(fileIdToLuResourceMap, triggerRules);
// do cross training from roots. One root one core training
for (const rootObjectId of rootObjectIds) {
@ -121,6 +48,101 @@ module.exports = {
}
},
/**
* Parse and validate luObject array to convert to LUResource object dict
* @param {luObject[]} luObjectArray the luObject list to be parsed
* @param {boolean} verbose indicate to enable log messages or not
* @returns {Map<string, LUResource>} Map of file id and luResource
* @throws {exception} Throws on errors. exception object includes errCode and text
*/
parseAndValidateLuContent: function (luObjectArray, verbose) {
let fileIdToLuResourceMap = new Map();
for (const luObject of luObjectArray) {
let luContent = luObject.content;
luContent = helpers.sanitizeNewLines(luContent);
if (luContent === undefined || luContent === '') continue;
let luResource = luParser.parse(luContent);
if (luResource.Errors && luResource.Errors.length > 0) {
if (verbose) {
var warns = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.WARN));
if (warns.length > 0) {
process.stdout.write(warns.map(warn => warn.toString()).join(NEWLINE).concat(NEWLINE));
}
}
var errors = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.ERROR));
if (errors.length > 0) {
throw (new exception(retCode.errorCode.INVALID_LINE, errors.map(error => error.toString()).join(NEWLINE)));
}
}
fileIdToLuResourceMap.set(luObject.id, luResource);
}
return fileIdToLuResourceMap;
},
/**
* Contruct resource tree to build the father-children relationship among lu files
* @param {Map<string, LUResource>} fileIdToLuResourceMap Map of file id and luResource
* @param {any} triggerRules trigger rules object that indicate the triggering rules from root to dest lu files
* @returns {any[]} Object array of LUResource with id and children properties
* @throws {exception} Throws on errors. exception object includes errCode and text
*/
constructResoureTree(fileIdToLuResourceMap, triggerRules) {
let visitedChildren = new Set();
let resources = [];
let fileIdsFromInput = Array.from(fileIdToLuResourceMap.keys());
for (const fileId of fileIdsFromInput) {
let luResource = fileIdToLuResourceMap.get(fileId);
let resource = {
id: fileId,
content: luResource,
children: []
};
if (!(fileId in triggerRules)) {
resources.push(resource);
continue;
}
let intents = [];
for (const section of luResource.Sections) {
if (section.SectionType === LUSectionTypes.SIMPLEINTENTSECTION
|| section.SectionType === LUSectionTypes.NESTEDINTENTSECTION) {
intents.push(section);
}
}
const destLuFileToIntent = triggerRules[fileId];
for (const destLuFile of Object.keys(destLuFileToIntent)) {
if (!fileIdsFromInput.includes(destLuFile)) continue;
if (visitedChildren.has(destLuFile)) {
// validate loop in a tree or forest
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, dialog call loop detected for lu file ${destLuFile} when doing cross training`));
}
const triggerIntentName = destLuFileToIntent[destLuFile];
if (!intents.some(i => i.Name === triggerIntentName)) {
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, trigger intent '${triggerIntentName}' is not found in lu file: ${fileId}`));
}
resource.children.push({
target: destLuFile,
intent: triggerIntentName
});
visitedChildren.add(destLuFile);
}
resources.push(resource);
}
return resources;
},
/**
* Cross training core function. Do cross training from a root to its children once.
* @param {string} rootResourceId the root resource object id
@ -144,16 +166,16 @@ module.exports = {
},
mergeRootInteruptionToLeaves: function (rootResource, result, intentName) {
if (rootResource && rootResource.children && rootResource.children.length > 0) {
this.mergeBrothersInteruption(rootResource, result, intentName)
for (const child of rootResource.children) {
let childResource = result.get(child.target);
if (childResource.visited === undefined) {
const newChildResource = this.mergeFatherInteruptionToChild(rootResource, childResource, intentName);
result.set(child.target, newChildResource);
newChildResource.visited = true;
this.mergeRootInteruptionToLeaves(newChildResource, result, intentName);
}
if (rootResource.children === undefined || rootResource.length <= 0) return;
this.mergeBrothersInteruption(rootResource, result, intentName)
for (const child of rootResource.children) {
let childResource = result.get(child.target);
if (childResource.visited === undefined) {
const newChildResource = this.mergeFatherInteruptionToChild(rootResource, childResource, intentName);
result.set(child.target, newChildResource);
newChildResource.visited = true;
this.mergeRootInteruptionToLeaves(newChildResource, result, intentName);
}
}
},
@ -205,34 +227,34 @@ module.exports = {
let newFileContent = '';
fromUtterances.forEach(utterance => {
if (!existingUtterances.includes(utterance)) {
newFileContent += '- ' + utterance + '\r\n';
newFileContent += '- ' + utterance + NEWLINE;
}
});
if (newFileContent !== '') {
newFileContent = toInteruption.ParseTree.intentDefinition().getText().trim() + '\r\n' + newFileContent;
let lines = newFileContent.split(/\r?\n/);
let newLines = [];
lines.forEach(line => {
if (line.trim().startsWith('-')) {
newLines.push('- ' + line.trim().slice(1).trim());
} else if (line.trim().startsWith('##')) {
newLines.push('## ' + line.trim().slice(2).trim());
} else if (line.trim().startsWith('#')) {
newLines.push('# ' + line.trim().slice(1).trim());
}
})
if (newFileContent === '') return toResource;
newFileContent = newLines.join('\r\n');
newFileContent = toInteruption.ParseTree.intentDefinition().getText().trim() + NEWLINE + newFileContent;
let lines = newFileContent.split(/\r?\n/);
let newLines = [];
lines.forEach(line => {
if (line.trim().startsWith('-')) {
newLines.push('- ' + line.trim().slice(1).trim());
} else if (line.trim().startsWith('##')) {
newLines.push('## ' + line.trim().slice(2).trim());
} else if (line.trim().startsWith('#')) {
newLines.push('# ' + line.trim().slice(1).trim());
}
})
// update section here
toResource.content = new SectionOperator(toResource.content).updateSection(toInteruption.Id, newFileContent);
}
newFileContent = newLines.join(NEWLINE);
// update section here
toResource.content = new SectionOperator(toResource.content).updateSection(toInteruption.Id, newFileContent);
} else {
// construct new content here
if (fromUtterances && fromUtterances.length > 0) {
let newFileContent = `\r\n# ${intentName}\r\n`;
fromUtterances.forEach(utterance => newFileContent += '- ' + utterance + '\r\n');
let newFileContent = NEWLINE + `# ${intentName}` + NEWLINE;
fromUtterances.forEach(utterance => newFileContent += '- ' + utterance + NEWLINE);
// add section here
toResource.content = new SectionOperator(toResource.content).addSection(newFileContent);