const parseFeatureSections = function()

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);
}