Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.

Commit 8f27460

Browse files
authored
fix (#926)
1 parent 9695b25 commit 8f27460

File tree

4 files changed

+63
-13
lines changed

4 files changed

+63
-13
lines changed

packages/lu/src/parser/lufile/parseFileContents.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ const parseLuAndQnaWithAntlr = async function (parsedContent, fileContent, log,
189189
updateIntentAndEntityFeatures(parsedContent.LUISJsonStructure);
190190

191191
helpers.checkAndUpdateVersion(parsedContent.LUISJsonStructure);
192-
192+
193193
}
194194

195195
const updateIntentAndEntityFeatures = function(luisObj) {
@@ -532,13 +532,7 @@ const parseFeatureSections = function(parsedContent, featuresToProcess) {
532532
validateFeatureAssignment(entityType, section.Name, INTENTTYPE, feature, section.Range);
533533
addFeatures(srcEntity, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.intentFeatureToModel);
534534
} else {
535-
// Item must be defined before being added as a feature.
536-
let errorMsg = `Features must be defined before assigned to an entity. No definition found for feature "${feature}" in usesFeature definition for entity "${section.Name}"`;
537-
let error = BuildDiagnostic({
538-
message: errorMsg,
539-
range: section.Range
540-
})
541-
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
535+
addFeatures(srcEntity, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.intentFeatureToModel);
542536
}
543537
});
544538
}

packages/lu/src/parser/luis/luisValidator.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const validateLUIS = function(luisJSON) {
2929
validateComposites(luisJSON, entitiesList)
3030
// do boundary validation
3131
validateBoundaries(luisJSON);
32+
// validate feature assignments
33+
validateFeatureAssignments(luisJSON);
3234
return true;
3335
}
3436
const validateBoundaries = function(luisJSON) {
@@ -313,6 +315,60 @@ const validateCompositeChildren = function(composite, entitiesList){
313315
})
314316
}
315317

318+
const validateFeatureAssignments = function(luisJSON)
319+
{
320+
const verifyList = [];
321+
const featureCandidates = [];
322+
const verifiedList = [];
323+
addFeatureCandidates(luisJSON.prebuiltEntities, featureCandidates);
324+
addFeatureCandidates(luisJSON.closedLists, featureCandidates);
325+
addFeatureCandidates(luisJSON.regex_entities, featureCandidates);
326+
addFeatureCandidates(luisJSON.phraselists, featureCandidates);
327+
verifyAndExtractFeatures(luisJSON.intents, verifyList, featureCandidates, verifiedList);
328+
verifyAndExtractFeatures(luisJSON.entities, verifyList, featureCandidates, verifiedList);
329+
verifyAndExtractFeatures(luisJSON.composites, verifyList, featureCandidates, verifiedList);
330+
if (verifyList.length !== 0) {
331+
verifyList.forEach(item => {
332+
if (!featureCandidates.includes(item)) {
333+
let errorMsg = `Feature "${item}" does not have a definition. All features must be defined.`;
334+
let error = BuildDiagnostic({ message: errorMsg });
335+
336+
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
337+
}
338+
})
339+
}
340+
}
341+
342+
const addFeatureCandidates = function(collection, featureCandidates)
343+
{
344+
(collection || []).forEach(item => {
345+
if (!featureCandidates.includes(item.name)) {
346+
featureCandidates.push(item.name);
347+
}
348+
})
349+
}
350+
351+
const verifyAndExtractFeatures = function(collection = [], verifyList = [], featureCandidates = [], verifiedList = []) {
352+
(collection || []).forEach(item => {
353+
if (!featureCandidates.includes(item.name)) {
354+
featureCandidates.push(item.name);
355+
}
356+
(item.features || []).forEach(feature => {
357+
let featureName = feature.modelName || feature.featureName || undefined;
358+
if (featureName !== undefined) {
359+
if (!verifiedList.includes(featureName)) {
360+
if (!featureCandidates.includes(featureName)) {
361+
if (!verifyList.includes(featureName)) {
362+
verifyList.push(featureName);
363+
}
364+
}
365+
}
366+
}
367+
})
368+
if (item.children && Array.isArray(item.children) && item.children.length !== 0) verifyAndExtractFeatures(item.children, verifyList, featureCandidates, verifiedList);
369+
})
370+
}
371+
316372
class validateLUISBlobEntity{
317373
constructor(name, type, roles) {
318374
this.name = name?name:'';

packages/lu/test/parser/lufile/parseFileContents.modelAsFeature.test.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License.
44
*/
5+
const luisBuilder = require('../../../src/parser/luis/luisBuilder');
56
const parseFile = require('../../../src/parser/lufile/parseFileContents');
67
const luconvert = require('../../../src/parser/luis/luConverter');
78
const entityNameWithSpaceAndFeature = require('../../fixtures/testcases/entityNameWithSpaceAndFeature.json');
@@ -196,8 +197,7 @@ describe('Model as feature definitions', function () {
196197
@ ml x1
197198
@ x1 usesFeature city3
198199
`;
199-
200-
parseFile.parseFile(luFile)
200+
luisBuilder.fromContentAsync(luFile)
201201
.then(res => done(res))
202202
.catch(err => done())
203203
});
@@ -435,11 +435,10 @@ describe('Model as feature definitions', function () {
435435
describe('Composite entity', function() {
436436
it('Features must be defined before they can be added.', function(done) {
437437
let luFile = `
438-
@ patternany x1
438+
@ composite x1
439439
@ x1 usesFeature city3
440440
`;
441-
442-
parseFile.parseFile(luFile)
441+
luisBuilder.fromContentAsync(luFile)
443442
.then(res => done(res))
444443
.catch(err => done())
445444
});

packages/luis/src/commands/luis/convert.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default class LuisConvert extends Command {
4545
if (isLu) {
4646
const luFiles = await file.getLuObjects(stdin, flags.in, flags.recurse, fileExtEnum.LUFile)
4747
result = await LuisBuilder.build(luFiles, flags.log, flags.culture)
48+
result.validate()
4849
if (!hasContent(result)) {
4950
throw new CLIError('No LU or Luis content parsed!')
5051
}

0 commit comments

Comments
 (0)