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

Commit 2c061ae

Browse files
axelsrzmunozemilio
andauthored
Changes to support Luis schema v6.0.0 (#534)
* initial changes to suppor 6.0.0 * logic for schema v6.0.0, testing pending * Luis schema v6.0.0 in luisgen c# * Update on test * Update on test * changing import style * changing import style * Fixing build and removing generate tests in LU * Basic test for schema v6.0.0 Co-authored-by: Emilio Munoz <[email protected]>
1 parent 475cc3d commit 2c061ae

File tree

25 files changed

+450
-339
lines changed

25 files changed

+450
-339
lines changed

packages/lu/src/parser/converters/luistocsconverter.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const parse_multi_platform_luis_1 = require("./../luis/propertyHelper");
22
const LuisGenBuilder = require('./../luis/luisGenBuilder')
3+
const exception = require('./../utils/exception');
34
const Writer = require("./helpers/writer");
5+
const lodash = require("lodash")
46

57
module.exports = {
68
writeFromLuisJson: async function(luisJson, className, space, outPath) {
@@ -115,7 +117,7 @@ module.exports = {
115117
writer.writeLine();
116118
}
117119
writer.writeLineIndented([
118-
`public class _Instance${composite.compositeName}`,
120+
`public class _Instance${lodash.upperFirst(composite.compositeName)}`,
119121
'{'
120122
]);
121123
writer.increaseIndentation();
@@ -127,7 +129,7 @@ module.exports = {
127129
writer.decreaseIndentation();
128130
writer.writeLineIndented([
129131
'}',
130-
`public class ${composite.compositeName}Class`,
132+
`public class ${lodash.upperFirst(composite.compositeName)}Class`,
131133
'{'
132134
]);
133135
writer.increaseIndentation();
@@ -137,12 +139,12 @@ module.exports = {
137139
});
138140
writer.writeLineIndented([
139141
'[JsonProperty("$instance")]',
140-
`public _Instance${composite.compositeName} _instance;`
142+
`public _Instance${lodash.upperFirst(composite.compositeName)} _instance;`
141143
]);
142144
writer.decreaseIndentation();
143145
writer.writeLineIndented([
144146
'}',
145-
`public ${composite.compositeName}Class[] ${composite.compositeName};`
147+
`public ${lodash.upperFirst(composite.compositeName)}Class[] ${composite.compositeName};`
146148
]);
147149
});
148150
}
@@ -170,7 +172,18 @@ module.exports = {
170172
'public _Entities Entities;'
171173
]);
172174
},
173-
getEntityWithType: function(entityName, entityType = '') {
175+
getEntityWithType: function(entityNameOrObject, entityType = '') {
176+
if (typeof entityNameOrObject === 'object' && 'name' in entityNameOrObject){
177+
if ('instanceOf' in entityNameOrObject){
178+
entityType = entityNameOrObject.instanceOf
179+
entityNameOrObject = entityNameOrObject.name
180+
} else if (entityNameOrObject.compositeInstanceOf) {
181+
let name = parse_multi_platform_luis_1.jsonPropertyName(entityNameOrObject.name)
182+
return `public ${lodash.upperFirst(name)}Class[] ${name};`
183+
} else {
184+
throw (new exception("Invalid LuisGen object: cannot parse entity"))
185+
}
186+
}
174187
let result = '';
175188
switch (entityType) {
176189
case 'age':
@@ -205,7 +218,7 @@ module.exports = {
205218
default:
206219
result = 'public string[]';
207220
}
208-
return result + ` ${parse_multi_platform_luis_1.jsonPropertyName(entityName)};`;
221+
return result + ` ${parse_multi_platform_luis_1.jsonPropertyName(entityNameOrObject)};`;
209222
},
210223
converter: function(className, writer) {
211224
writer.writeLine();

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

Lines changed: 119 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,52 @@ const retCode = require('./../utils/enums/CLI-errors')
55

66
class LuisGenBuilder {
77
static build(luisApp) {
8-
let result = new LuisGen()
9-
try {
10-
result.intents = processIntents(luisApp.intents);
11-
result.entities = extractEntities(luisApp.entities);
12-
result.prebuiltEntities = extractEntities(luisApp.prebuiltEntities, true);
13-
result.closedLists = extractEntities(luisApp.closedLists);
14-
result.regex_entities = extractEntities(luisApp.regex_entities);
15-
result.patternAnyEntities = extractEntities(luisApp.patternAnyEntities);
16-
result.composites = extractComposites(luisApp.composites);
17-
} catch (err) {
18-
throw (new error(retCode.errorCode.INVALID_INPUT_FILE, "Invalid LUIS JSON file content."))
8+
let buildWithVersion;
9+
if (luisApp.luis_schema_version < "5") {
10+
buildWithVersion = buildUpToVersion4;
11+
} else if (luisApp.luis_schema_version >= "6.0.0") {
12+
buildWithVersion = buildVersion6;
13+
} else {
14+
throw (new error(retCode.errorCode.INVALID_INPUT_FILE, "Invalid LUIS JSON schema version."))
1915
}
20-
return result
16+
17+
return buildWithVersion(luisApp);
2118
}
2219
}
2320

2421
module.exports = LuisGenBuilder
2522

23+
const buildUpToVersion4 = function(luisApp) {
24+
let result = new LuisGen()
25+
try {
26+
result.intents = processIntents(luisApp.intents);
27+
result.entities = extractEntities(luisApp.entities);
28+
result.prebuiltEntities = extractEntities(luisApp.prebuiltEntities, true);
29+
result.closedLists = extractEntities(luisApp.closedLists);
30+
result.regex_entities = extractEntities(luisApp.regex_entities);
31+
result.patternAnyEntities = extractEntities(luisApp.patternAnyEntities);
32+
result.composites = extractComposites(luisApp.composites);
33+
} catch (err) {
34+
throw (new error(retCode.errorCode.INVALID_INPUT_FILE, "Invalid LUIS JSON file content."))
35+
}
36+
return result
37+
}
38+
39+
const buildVersion6 = function(luisApp) {
40+
let result = new LuisGen()
41+
try {
42+
result.intents = processIntents(luisApp.intents);
43+
[result.entities, result.composites] = extractEntitiesV6(luisApp.entities);
44+
result.prebuiltEntities = extractEntities(luisApp.prebuiltEntities, true);
45+
result.closedLists = extractEntities(luisApp.closedLists);
46+
result.regex_entities = extractEntities(luisApp.regex_entities);
47+
result.patternAnyEntities = extractEntities(luisApp.patternAnyEntities);
48+
} catch (err) {
49+
throw (new error(retCode.errorCode.INVALID_INPUT_FILE, "Invalid LUIS JSON file content."))
50+
}
51+
return result
52+
}
53+
2654
const processIntents = function(intents) {
2755
const result = [];
2856
intents.forEach((intent) => {
@@ -69,4 +97,83 @@ const extractEntities = function(entities, builtIn = false) {
6997
}
7098
});
7199
return result;
100+
}
101+
102+
const extractEntitiesV6 = function(entities) {
103+
// This method provides a simplified topological sort to
104+
// solve potential instanceOf dependecies in the v6 entities
105+
106+
const simpleEntitiesResult = [];
107+
const compositeEntitiesResult = [];
108+
const simpleEntitiesWithType = {};
109+
const resolveEntityType = function(entityName) {
110+
const entityStack = [];
111+
let entityType = simpleEntitiesWithType[entityName];
112+
113+
while (simpleEntitiesWithType[entityType]){
114+
entityStack.push(entityName);
115+
entityName = entityType;
116+
entityType = simpleEntitiesWithType[entityName];
117+
}
118+
119+
while (entityName) {
120+
simpleEntitiesWithType[entityName] = entityType;
121+
entityName = entityStack.pop();
122+
}
123+
}
124+
125+
const firstPassStack = entities.slice();
126+
127+
while(firstPassStack.length) {
128+
const entity = firstPassStack.pop();
129+
130+
if (Array.isArray(entity.children) && entity.children.length) {
131+
firstPassStack.push(...entity.children);
132+
} else if (!entity.children || (Array.isArray(entity.children) && entity.children.length == 0)) {
133+
// is simple entity
134+
if (entity.instanceOf) {
135+
// If the entity order in the schema was not modified by hand,
136+
// this algorithm will solve instanceOf dependencies.
137+
const last_type = simpleEntitiesWithType[entity.instanceOf] || entity.instanceOf;
138+
simpleEntitiesWithType[entity.name] = last_type;
139+
}
140+
} else {
141+
throw CLIError("Malformed JSON: entity.children should be an array");
142+
}
143+
}
144+
145+
// This is a second pass for simple entities.
146+
// If the JSON was modified by hand and there's a dependency
147+
// in the instanceOf field to an entity that appears later,
148+
// the type won't be resolved correctly with one pass.
149+
for (const entityName in simpleEntitiesWithType) {
150+
resolveEntityType(entityName);
151+
}
152+
153+
const processSimpleEntity = function(entity, listToAppend) {
154+
listToAppend.push(
155+
entity.instanceOf ? {name: entity.name, instanceOf: simpleEntitiesWithType[entity.instanceOf] || entity.instanceOf} : entity.name
156+
)
157+
}
158+
159+
const baseParseEntity = function(entityList, childList, topLevel=false) {
160+
entityList.forEach(entity => {
161+
if (Array.isArray(entity.children) && entity.children.length) {
162+
const compositeEntity = { compositeName: propertyHelper.normalizeName(entity.name), attributes: [] };
163+
baseParseEntity(entity.children, compositeEntity.attributes);
164+
compositeEntitiesResult.push(compositeEntity);
165+
if (!topLevel) {
166+
childList.push({name: entity.name, compositeInstanceOf: true})
167+
}
168+
} else {
169+
processSimpleEntity(
170+
entity,
171+
topLevel ? simpleEntitiesResult : childList
172+
)
173+
}
174+
});
175+
}
176+
177+
baseParseEntity(entities, null, true);
178+
return [simpleEntitiesResult, compositeEntitiesResult];
72179
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11

22
module.exports = {
33
jsonPropertyName: function(property) {
4+
if (typeof property === 'object') {
5+
property = property.name
6+
}
47
property+= ''
58
let name = property.split(':').slice(-1)[0];
69
if (!name.startsWith('geographyV2') &&

packages/lu/test/commands/luis/generate/cs.test.ts

Lines changed: 0 additions & 143 deletions
This file was deleted.

0 commit comments

Comments
 (0)