in parsers/LU/JS/packages/lu/src/parser/lufile/parseFileContents.js [446:544]
const parseFeatureSections = function(parsedContent, featuresToProcess) {
// We are only interested in extracting features and setting things up here.
(featuresToProcess || []).forEach(section => {
if (section.Type === INTENTTYPE) {
// Intents can only have features and nothing else.
if (section.Roles) {
let errorMsg = `Intents can only have usesFeature and nothing else. Invalid definition for "${section.Name}".`;
let error = BuildDiagnostic({
message: errorMsg,
range: section.Range
})
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
}
if (!section.Features) return;
// verify intent exists
section.Name = section.Name.replace(/[\'\"]/g, "");
let intentExists = parsedContent.LUISJsonStructure.intents.find(item => item.name === section.Name);
if (intentExists !== undefined) {
// verify the list of features requested have all been defined.
let featuresList = section.Features.split(/[,;]/g).map(item => item.trim().replace(/^[\'\"]|[\'\"]$/g, ""));
(featuresList || []).forEach(feature => {
let entityExists = (parsedContent.LUISJsonStructure.flatListOfEntityAndRoles || []).find(item => item.name == feature || item.name == `${feature}(interchangeable)`);
let featureIntentExists = (parsedContent.LUISJsonStructure.intents || []).find(item => item.name == feature);
if (entityExists) {
if (entityExists.type === EntityTypeEnum.PHRASELIST) {
// de-dupe and add features to intent.
validateFeatureAssignment(section.Type, section.Name, entityExists.type, feature, section.Range);
addFeatures(intentExists, feature, featureTypeEnum.featureToModel, section.Range, featureProperties.phraseListFeature);
// set enabledForAllModels on this phrase list
let plEnity = parsedContent.LUISJsonStructure.model_features.find(item => item.name == feature);
if (plEnity.enabledForAllModels === undefined) plEnity.enabledForAllModels = false;
} else {
// de-dupe and add model to intent.
validateFeatureAssignment(section.Type, section.Name, entityExists.type, feature, section.Range);
addFeatures(intentExists, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.entityFeatureToModel[entityExists.type]);
}
} else if (featureIntentExists) {
// Add intent as a feature to another intent
validateFeatureAssignment(section.Type, section.Name, INTENTTYPE, feature, section.Range);
addFeatures(intentExists, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.intentFeatureToModel);
} else {
// Item must be defined before being added as a feature.
let errorMsg = `Features must be defined before assigned to an intent. No definition found for feature "${feature}" in usesFeature definition for intent "${section.Name}"`;
let error = BuildDiagnostic({
message: errorMsg,
range: section.Range
})
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
}
})
} else {
let errorMsg = `Features can only be added to intents that have a definition. Invalid feature definition found for intent "${section.Name}".`;
let error = BuildDiagnostic({
message: errorMsg,
range: section.Range
})
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
}
} else {
// handle as entity
if (section.Features) {
let featuresList = section.Features.split(/[,;]/g).map(item => item.trim());
// Find the source entity from the collection and get its type
let srcEntityInFlatList = (parsedContent.LUISJsonStructure.flatListOfEntityAndRoles || []).find(item => item.name == section.Name);
let entityType = srcEntityInFlatList ? srcEntityInFlatList.type : undefined;
(featuresList || []).forEach(feature => {
feature = feature.replace(/[\'\"]/g, "");
let featureExists = (parsedContent.LUISJsonStructure.flatListOfEntityAndRoles || []).find(item => item.name == feature || item.name == `${feature}(interchangeable)`);
let featureIntentExists = (parsedContent.LUISJsonStructure.intents || []).find(item => item.name == feature);
// find the entity based on its type.
let srcEntity = (parsedContent.LUISJsonStructure[luisEntityTypeMap[entityType]] || []).find(item => item.name == section.Name);
if (featureExists) {
if (featureExists.type === EntityTypeEnum.PHRASELIST) {
// de-dupe and add features to intent.
validateFeatureAssignment(entityType, section.Name, featureExists.type, feature, section.Range);
addFeatures(srcEntity, feature, featureTypeEnum.featureToModel, section.Range, featureProperties.phraseListFeature);
// set enabledForAllModels on this phrase list
let plEnity = parsedContent.LUISJsonStructure.model_features.find(item => item.name == feature);
if (plEnity.enabledForAllModels === undefined) plEnity.enabledForAllModels = false;
} else {
// de-dupe and add model to intent.
validateFeatureAssignment(entityType, section.Name, featureExists.type, feature, section.Range);
addFeatures(srcEntity, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.entityFeatureToModel[featureExists.type]);
}
} else if (featureIntentExists) {
// Add intent as a feature to another intent
validateFeatureAssignment(entityType, section.Name, INTENTTYPE, feature, section.Range);
addFeatures(srcEntity, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.intentFeatureToModel);
} else {
addFeatures(srcEntity, feature, featureTypeEnum.modelToFeature, section.Range, featureProperties.intentFeatureToModel);
}
});
}
}
});
// Circular dependency for features is not allowed. E.g. A usesFeature B usesFeature A is not valid.
verifyNoCircularDependencyForFeatures(parsedContent);
}