diff --git a/packages/lu/src/parser/lufile/parseFileContents.js b/packages/lu/src/parser/lufile/parseFileContents.js index 62ed2ce22..96bfdad68 100644 --- a/packages/lu/src/parser/lufile/parseFileContents.js +++ b/packages/lu/src/parser/lufile/parseFileContents.js @@ -1390,11 +1390,11 @@ const parseAndHandleEntityV2 = function (parsedContent, luResource, log, locale, case EntityTypeEnum.COMPOSITE: let candidateChildren = []; if (entity.CompositeDefinition) { - entity.CompositeDefinition.replace(/[\[\]]/g, '').split(/[,;]/g).map(item => item.trim()).forEach(item => candidateChildren.push(item)); + entity.CompositeDefinition.replace(/[\[\]]/g, '').split(/[,;]/g).map(item => item.trim()).filter(s => s).forEach(item => candidateChildren.push(item)); } if (entity.ListBody) { entity.ListBody.forEach(line => { - line.trim().substr(1).trim().replace(/[\[\]]/g, '').split(/[,;]/g).map(item => item.trim()).forEach(item => candidateChildren.push(item)); + line.trim().substr(1).trim().replace(/[\[\]]/g, '').split(/[,;]/g).map(item => item.trim()).filter(s => s).forEach(item => candidateChildren.push(item)); }) } handleComposite(parsedContent, entityName,`[${candidateChildren.join(',')}]`, entityRoles, entity.Range, false, entity.Type !== undefined, config); @@ -1467,7 +1467,7 @@ const handleNDepthEntity = function(parsedContent, entityName, entityRoles, enti } let childEntityName = groupsFound.groups.entityName.replace(/^['"]/g, '').replace(/['"]$/g, ''); let childEntityType = groupsFound.groups.instanceOf.trim(); - let childFeatures = groupsFound.groups.features ? groupsFound.groups.features.trim().split(/[,;]/g).map(item => item.trim()) : undefined; + let childFeatures = groupsFound.groups.features ? groupsFound.groups.features.trim().split(/[,;]/g).map(item => item.trim()).filter(s => s) : undefined; // Get current tab level let tabLevel = Math.ceil(groupsFound.groups.leadingSpaces !== undefined ? groupsFound.groups.leadingSpaces.length / SPACEASTABS : 0) || (groupsFound.groups.leadingTabs !== undefined ? groupsFound.groups.leadingTabs.length : 0); @@ -1682,7 +1682,7 @@ const handlePhraseList = function(parsedContent, entityName, entityType, entityR // add this to phraseList if it doesnt exist let pLValues = []; for (const phraseListValues of valuesList) { - phraseListValues.split(/[,;]/g).map(item => item.trim()).forEach(item => pLValues.push(item)); + phraseListValues.split(/[,;]/g).map(item => item.trim()).filter(s => s).forEach(item => pLValues.push(item)); } let pLEntityExists = parsedContent.LUISJsonStructure.model_features.find(item => item.name == entityName); @@ -1902,7 +1902,7 @@ const handleClosedList = function (parsedContent, entityName, listLines, entityR addNV = true; } } else { - line.split(/[,;]/g).forEach(item => { + line.split(/[,;]/g).filter(s => s.trim()).forEach(item => { item = item.trim(); if (!nvExists || !nvExists.list) { let errorMsg = `Closed list ${entityName} has synonyms list "${line}" without a normalized value.`; diff --git a/packages/lu/test/parser/lufile/parseFileContents.NewEntityDefinition.test.js b/packages/lu/test/parser/lufile/parseFileContents.NewEntityDefinition.test.js index fe26e68f7..69b270f69 100644 --- a/packages/lu/test/parser/lufile/parseFileContents.NewEntityDefinition.test.js +++ b/packages/lu/test/parser/lufile/parseFileContents.NewEntityDefinition.test.js @@ -716,6 +716,22 @@ describe('V2 Entity definitions using @ notation', function () { .then(res => done(res)) .catch(err => done()) }); + + it('Phrase list definition with semicolon at the end of words is handled correctly', function(done) { + let luFile = ` + @phraselist xyz + - x, y, z, + `; + + parseFile.parseFile(luFile) + .then(res => { + assert.equal(res.LUISJsonStructure.model_features.length, 1); + assert.equal(res.LUISJsonStructure.model_features[0].name, 'xyz'); + assert.equal(res.LUISJsonStructure.model_features[0].words, 'x,y,z'); + done(); + }) + .catch(err => done(err)) + }); }); describe('Prebuilt entity types', function(done) { @@ -927,6 +943,25 @@ describe('V2 Entity definitions using @ notation', function () { .catch(err => done(err)) }); + it('Basic list child definition with semicolon at the end is handled correctly', function(done) { + let luFile = ` + @composite name hasRoles r1, r2 = + - child1;child2; + `; + + parseFile.parseFile(luFile) + .then(res => { + assert.equal(res.LUISJsonStructure.composites.length, 1); + assert.equal(res.LUISJsonStructure.composites[0].name, 'name'); + assert.equal(res.LUISJsonStructure.composites[0].roles.length, 2); + assert.deepEqual(res.LUISJsonStructure.composites[0].roles, ['r1', 'r2']); + assert.equal(res.LUISJsonStructure.composites[0].children.length, 2); + assert.deepEqual(res.LUISJsonStructure.composites[0].children, ['child1', 'child2']); + done(); + }) + .catch(err => done(err)) + }); + it('Definition can be split up in various ways', function(done) { let luFile = ` @composite name @@ -1097,6 +1132,29 @@ describe('V2 Entity definitions using @ notation', function () { }) .catch(err => done(err)) }) + + it('Synonymous definition with semicolon at the end is handled correctly', function(done){ + let luFile = ` + @list x1 = + - a1: + - one;two; + - a2: + -three;four; + `; + + parseFile.parseFile(luFile) + .then(res => { + assert.equal(res.LUISJsonStructure.closedLists.length, 1); + assert.equal(res.LUISJsonStructure.closedLists[0].name, 'x1'); + assert.equal(res.LUISJsonStructure.closedLists[0].subLists.length, 2); + assert.equal(res.LUISJsonStructure.closedLists[0].subLists[0].canonicalForm, 'a1'); + assert.deepEqual(res.LUISJsonStructure.closedLists[0].subLists[0].list, ['one', 'two']); + assert.equal(res.LUISJsonStructure.closedLists[0].subLists[1].canonicalForm, 'a2'); + assert.deepEqual(res.LUISJsonStructure.closedLists[0].subLists[1].list, ['three', 'four']); + done(); + }) + .catch(err => done(err)) + }); }); describe('Pattern.Any entity definition', function(){ diff --git a/packages/lu/test/parser/lufile/parseFileContents.nDepthEntity.test.js b/packages/lu/test/parser/lufile/parseFileContents.nDepthEntity.test.js index 4fef09c98..b9072bf36 100644 --- a/packages/lu/test/parser/lufile/parseFileContents.nDepthEntity.test.js +++ b/packages/lu/test/parser/lufile/parseFileContents.nDepthEntity.test.js @@ -816,4 +816,21 @@ describe('V2 NDepth definitions using @ notation', function () { .catch(err => done()) }) + it('nDepth useFeatures can have semicolon at the end of feature list', function(done){ + let luFile = ` +@ ml nDepth usesFeatures phraselist1 + - @ ml nDepth_child2 usesFeatures phraselist1, +@ phraselist phraselist1(interchangeable) = + - who,why,where,what + `; + + parseFile.parseFile(luFile) + .then(res => { + assert.equal(res.LUISJsonStructure.entities.length, 1); + assert.equal(res.LUISJsonStructure.entities[0].features[0].featureName, 'phraselist1'); + assert.equal(res.LUISJsonStructure.entities[0].children[0].features[0].featureName, 'phraselist1'); + done(); + }) + .catch(err => done(err)) + }); }); \ No newline at end of file