in packages/lu/src/parser/lufile/parseFileContents.js [1944:2058]
const parseAndHandleEntitySection = function (parsedContent, luResource, log, locale, config) {
// handle entity
let entities = luResource.Sections.filter(s => s.SectionType === SectionType.ENTITYSECTION);
if (entities && entities.length > 0) {
for (const entity of entities) {
let entityName = entity.Name;
let entityType = entity.Type;
if (entityType !== EntityTypeEnum.PHRASELIST && InvalidCharsInIntentOrEntityName.some(x => entityName.includes(x))) {
let errorMsg = `Invalid entity line, entity name ${entityName} cannot contain any of the following characters: [<, >, *, %, &, :, \\, $]`;
throwDiagnosticError({
message: errorMsg,
line: entity.Range.Start.Line
});
}
let parsedRoleAndType = helpers.getRolesAndType(entityType);
let entityRoles = parsedRoleAndType.roles;
entityType = parsedRoleAndType.entityType;
let pEntityName = (entityName.toLowerCase() === 'prebuilt') ? entityType : entityName;
let PAEntityRoles = RemoveDuplicatePatternAnyEntity(parsedContent, pEntityName, entityType, entity.Range);
if (PAEntityRoles.length > 0) {
PAEntityRoles.forEach(role => {
if (!entityRoles.includes(role)) entityRoles.push(role);
})
}
// add this entity to appropriate place
// is this a builtin type?
if (builtInTypes.consolidatedList.map(item => item.toLowerCase()).includes(entityType.toLowerCase())) {
handlePrebuiltEntity(parsedContent, entityName, entityType, entityRoles, locale, log, entity.Range, config);
} else if (entityType.toLowerCase() === 'simple') {
// add this to entities if it doesnt exist
addItemOrRoleIfNotPresent(parsedContent.LUISJsonStructure, LUISObjNameEnum.ENTITIES, entityName, entityRoles);
let rootEntity = parsedContent.LUISJsonStructure.entities.find(item => item.name == entityName);
rootEntity.explicitlyAdded = true;
} else if (entityType.endsWith('=')) {
// is this qna maker alterations list?
if (entityType.includes(PARSERCONSTS.QNAALTERATIONS)) {
let alterationlist = [entity.Name];
if (entity.SynonymsOrPhraseList && entity.SynonymsOrPhraseList.length > 0) {
alterationlist = alterationlist.concat(entity.SynonymsOrPhraseList);
parsedContent.qnaAlterations.wordAlterations.push(new qnaAlterations().wordAlterations = {"alterations": alterationlist});
} else {
let errorMsg = `QnA alteration section: "${alterationlist}" does not have list decoration. Prefix line with "-" or "+" or "*"`;
throwDiagnosticError({
message: errorMsg,
range: entity.range,
errorCode: retCode.errorCode.SYNONYMS_NOT_A_LIST
});
}
} else {
// treat this as a LUIS list entity type
let parsedEntityTypeAndRole = helpers.getRolesAndType(entityType);
entityType = parsedEntityTypeAndRole.entityType;
(parsedEntityTypeAndRole.roles || []).forEach(role => !entityRoles.includes(role) ? entityRoles.push(role) : undefined);
// check if this list entity is already labelled in an utterance and or added as a simple entity. if so, throw an error.
try {
let rolesImport = VerifyAndUpdateSimpleEntityCollection(parsedContent, entityName, 'List');
if (rolesImport.length !== 0) {
rolesImport.forEach(role => {
if (!entityRoles.includes(role)) {
entityRoles.push(role)
}
})
}
} catch (err) {
throw (err);
}
// get normalized value
let normalizedValue = entityType.substring(0, entityType.length - 1).trim();
let synonymsList = entity.SynonymsOrPhraseList;
let closedListExists = helpers.filterMatch(parsedContent.LUISJsonStructure.closedLists, 'name', entityName);
if (closedListExists.length === 0) {
parsedContent.LUISJsonStructure.closedLists.push(new helperClass.closedLists(entityName, [new helperClass.subList(normalizedValue, synonymsList)], entityRoles));
} else {
// closed list with this name already exists
let subListExists = helpers.filterMatch(closedListExists[0].subLists, 'canonicalForm', normalizedValue);
if (subListExists.length === 0) {
closedListExists[0].subLists.push(new helperClass.subList(normalizedValue, synonymsList));
} else {
synonymsList.forEach(function (listItem) {
if (!subListExists[0].list.includes(listItem)) subListExists[0].list.push(listItem);
})
}
// see if the roles all exist and if not, add them
mergeRoles(closedListExists[0].roles, entityRoles);
}
}
} else if (entityType.toLowerCase().trim().indexOf('phraselist') === 0) {
if (entityType.toLowerCase().includes('interchangeable')) {
entityName += '(interchangeable)';
}
handlePhraseList(parsedContent, entityName, entityType, entityRoles, entity.SynonymsOrPhraseList, entity.Range, config);
} else if (entityType.startsWith('[')) {
handleComposite(parsedContent, entityName, entityType, entityRoles, entity.Range, true, true, config);
} else if (entityType.startsWith('/')) {
if (entityType.endsWith('/')) {
handleRegExEntity(parsedContent, entityName, entityType, entityRoles, entity.Range, config);
} else {
let errorMsg = `RegEx entity: ${regExEntity.name} is missing trailing '/'. Regex patterns need to be enclosed in forward slashes. e.g. /[0-9]/`;
throwDiagnosticError({
message: errorMsg,
range: entity.Range,
errorCode: retCode.errorCode.INVALID_REGEX_ENTITY
});
}
} else {
// TODO: handle other entity types
}
}
}
};