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

Commit 016a981

Browse files
committed
Luis refactor and error fixing for writing output
1 parent 2c50f78 commit 016a981

File tree

12 files changed

+116
-265
lines changed

12 files changed

+116
-265
lines changed

packages/luis/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
},
3939
"files": [
4040
"/lib",
41+
"/parser",
4142
"/npm-shrinkwrap.json",
4243
"/oclif.manifest.json"
4344
],

packages/luis/parser/converters/luistoluconverter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const path = require('path')
44
const txtfile = require('./../lufile/read-text-file')
55
const luisFile = require('./../luisfile/parseLuisFile')
66
const helperClasses = require('./../lufile/classes/hclasses')
7-
const exception = ('./../lufile/classes/exception')
7+
const exception = require('./../lufile/classes/exception')
88
const retCode = require('./../lufile/enums/CLI-errors')
99

1010
module.exports = {

packages/luis/parser/converters/qnajsontoqnaconverter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const path = require('path')
44
const txtfile = require('./../lufile/read-text-file')
55
const qnaFile = require('./../qnafile/parseQnAFile')
66
const helperClasses = require('./../lufile/classes/hclasses')
7-
const exception = ('./../lufile/classes/exception')
7+
const exception = require('./../lufile/classes/exception')
88
const retCode = require('./../lufile/enums/CLI-errors')
99

1010
module.exports = {

packages/luis/parser/luisfile/parseLuisFile.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const exception = ('./../lufile/classes/exception')
1+
const exception = require('./../lufile/classes/exception')
22
const helpers = require('./../lufile/helpers');
33
const retCode = require('./../lufile/enums/CLI-errors');
44
const helperClass = require('./../lufile/classes/hclasses');
@@ -12,9 +12,7 @@ module.exports = {
1212
} catch (err) {
1313
throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, error parsing file as LUIS JSON: ' + file));
1414
}
15-
if(!await validateLUISJSON(LUISJSON)){
16-
throw(new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, invalid input LUIS JSON. Cannot convert to .lu file.'));
17-
}
15+
await validateLUISJSON(LUISJSON)
1816
return LUISJSON;
1917
},
2018
/**
@@ -175,10 +173,9 @@ module.exports = {
175173

176174
const validateLUISJSON = async function(LUISJSON) {
177175
if(!LUISJSON.intents && !LUISJSON.entities) {
178-
return false;
176+
throw new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, input LUIS JSON file has no intents and entities');
179177
}
180178
if(LUISJSON.regex_features && LUISJSON.regex_features.length !== 0) {
181-
throw(new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, input LUIS JSON file has references to regex_features. Cannot convert to .lu file.'));
179+
throw new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, input LUIS JSON file has references to regex_features. Cannot convert to .lu file.');
182180
}
183-
return true;
184181
}

packages/luis/parser/translator/lutranslate.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ module.exports = {
1313
let file = files[i++] + ''
1414
try {
1515
let luObject = await parseFile(file)
16-
translation[path.basename(file)] = await translateLuObject(luObject, translate_key, to_lang, src_lang, translate_comments, translate_link_text)
16+
translation[path.basename(file)] = await this.translateLuObj(luObject, translate_key, to_lang, src_lang, translate_comments, translate_link_text)
1717
} catch (err) {
1818
throw(err);
1919
}
2020
}
2121
return translation
2222
},
23-
translateLuObject: async function(luObject, translate_key, to_lang, src_lang, translate_comments, translate_link_text) {
23+
translateLuObj: async function(luObject, translate_key, to_lang, src_lang, translate_comments, translate_link_text) {
2424
let translation = {}
2525
try {
26-
translation['luTranslation'] = await translateLuObject(luObject, translate_key, to_lang, src_lang, translate_comments, translate_link_text)
26+
translation = await translateLuObject(luObject, translate_key, to_lang, src_lang, translate_comments, translate_link_text)
2727
} catch (err) {
2828
throw(err);
2929
}

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

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {CLIError, Command, flags} from '@microsoft/bf-cli-command'
22
const exception = require('./../../../parser/lufile/classes/exception')
33
const fs = require('fs-extra')
44
const path = require('path')
5-
const helpers = require('./../../../parser/lufile/helpers')
5+
const file = require('./../../utils/filehelper')
66
const luConverter = require('./../../../parser/converters/lutoluisconverter')
77
const luisConverter = require('./../../../parser/converters/luistoluconverter')
88

@@ -22,20 +22,18 @@ export default class LuisConvert extends Command {
2222
schemaversion: flags.string({description: 'Schema version of the LUIS application'}),
2323
}
2424

25-
inputStat: any
26-
2725
async run() {
2826
try {
2927
const {flags} = this.parse(LuisConvert)
3028
//Check if file or folder
3129
//if folder, only lu to luis is supported
32-
this.inputStat = await fs.stat(flags.in)
33-
let isLu = !this.inputStat.isFile() ? true : path.extname(flags.in) === '.lu'
30+
let inputStat = await fs.stat(flags.in)
31+
let isLu = !inputStat.isFile() ? true : path.extname(flags.in) === '.lu'
3432

3533
// Parse the object depending on the input
3634
let result: any
3735
if (isLu) {
38-
let luFiles = await this.getLuFiles(flags.in, flags.recurse)
36+
let luFiles = await file.getLuFiles(flags.in, flags.recurse)
3937
result = await luConverter.parseLuToLuis(luFiles, flags.log, flags.culture)
4038
} else {
4139
result = await luisConverter.parseLuisFileToLu(flags.in, flags.sort)
@@ -71,28 +69,8 @@ export default class LuisConvert extends Command {
7169
}
7270
}
7371

74-
private async getLuFiles(input: string | undefined, recurse = false): Promise<Array<any>> {
75-
let filesToParse = []
76-
77-
if (this.inputStat.isFile()) {
78-
filesToParse.push(input)
79-
return filesToParse
80-
}
81-
82-
if (!this.inputStat.isDirectory()) {
83-
throw new CLIError('Sorry, ' + input + ' is not a folder or does not exist')
84-
}
85-
86-
filesToParse = helpers.findLUFiles(input, recurse)
87-
88-
if (filesToParse.length === 0) {
89-
throw new CLIError('Sorry, no .lu files found in the specified folder.')
90-
}
91-
return filesToParse
92-
}
93-
9472
private async writeOutput(convertedObject: any, flags: any, isLu: boolean) {
95-
let filePath = await this.generateNewFilePath(flags.out, flags.in, isLu)
73+
let filePath = await file.generateNewFilePath(flags.out, flags.in, isLu)
9674
// write out the final file
9775
try {
9876
await fs.writeFile(filePath, convertedObject, 'utf-8')
@@ -102,21 +80,4 @@ export default class LuisConvert extends Command {
10280
}
10381
this.log('Successfully wrote LUIS model to ' + filePath)
10482
}
105-
106-
private async generateNewFilePath(outFileName: string, inputfile: string, isLu: boolean): Promise<string> {
107-
let extension = path.extname(outFileName)
108-
if (extension === '.json' || extension === '.lu') {
109-
return path.join(process.cwd(), outFileName)
110-
}
111-
112-
let base = path.join(process.cwd(), outFileName)
113-
await fs.mkdirp(base)
114-
let name
115-
if (this.inputStat.isFile()) {
116-
name = path.basename(inputfile, path.extname(inputfile)) + (isLu ? '.json' : '.lu')
117-
} else {
118-
name = isLu ? 'lufile.lu' : 'luisapp.json'
119-
}
120-
return path.join(base, name)
121-
}
12283
}
Lines changed: 25 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,76 @@
11
import {CLIError, Command, flags} from '@microsoft/bf-cli-command'
22
const fs = require('fs-extra')
33
const path = require('path')
4-
const helpers = require('./../../../parser/lufile/helpers')
4+
const fileHelper = require('./../../utils/filehelper')
5+
const exception = require('./../../../parser/lufile/classes/exception')
56
const luTranslator = require('./../../../parser/translator/lutranslate')
67
const luisConverter = require('./../../../parser/converters/luistoluconverter')
7-
const luConverter = require('./../../../parser/converters/lutoluisconverter')
8+
const luConverter = require('./../../../parser/lufile/parseFileContents')
89

910
export default class LuisTranslate extends Command {
1011
static description = ' Translate given LUIS application JSON model or lu file(s)'
1112

1213
static flags: flags.Input<any> = {
1314
in: flags.string({description: 'Source .lu file(s) or LUIS application JSON model', required: true}),
1415
recurse: flags.boolean({description: 'Indicates if sub-folders need to be considered to file .lu file(s)'}),
15-
out: flags.string({description: 'Output file or folder name. If not specified stdout will be used as output'}),
16+
out: flags.string({description: 'Output folder name. If not specified stdout will be used as output'}),
1617
srclang: flags.string({description: 'Source lang code. Auto detect if missing.'}),
1718
tgtlang: flags.string({description: 'Comma separated list of target languages.', required: true}),
1819
translatekey: flags.string({description: 'Machine translation endpoint key.', required: true}),
1920
translate_comments: flags.string({description: 'When set, machine translate comments found in .lu or .qna file'}),
2021
translate_link_text: flags.string({description: 'When set, machine translate link description in .lu or .qna file'}),
2122
}
2223

23-
inputStat: any
24-
24+
/* tslint:disable:forin no-for-in*/
2525
async run() {
2626
try {
2727
const {flags} = this.parse(LuisTranslate)
28-
this.inputStat = await fs.stat(flags.in)
28+
let inputStat = await fs.stat(flags.in)
2929
let outputStat = flags.out ? await fs.stat(flags.out) : undefined
3030

31-
if (!this.inputStat.isFile() && outputStat && outputStat.isFile()) {
32-
throw new CLIError('Specified output cannot be applied to input')
31+
if (outputStat && outputStat.isFile()) {
32+
throw new CLIError('Output can only be writen to a folder')
3333
}
3434

35-
let isLu = !this.inputStat.isFile() ? true : path.extname(flags.in) === '.lu'
35+
let isLu = !inputStat.isFile() ? true : path.extname(flags.in) === '.lu'
3636
let result: any
37-
let luFiles: any
3837
if (isLu) {
39-
luFiles = await this.getLuFiles(flags.in, flags.recurse)
38+
let luFiles = await fileHelper.getLuFiles(flags.in, flags.recurse)
4039
result = await luTranslator.translateLuFile(luFiles, flags.translatekey, flags.tgtlang, flags.srclang, flags.translate_comments, flags.translate_link_text)
4140
} else {
42-
result = await luisConverter.parseLuisFileToLu(flags.in, false)
43-
result = await luTranslator.translateLuObject(result, flags.translatekey, flags.tgtlang, flags.srclang, flags.translate_comments, flags.translate_link_text)
44-
let tempFile = path.join(__dirname, 'tempfile')
45-
await fs.writeFile(tempFile, result['luTranslation'][flags.tgtlang])
46-
result = await luConverter.parseLuToLuis([tempFile], false, undefined)
47-
await fs.remove(tempFile)
41+
let translation = await luisConverter.parseLuisFileToLu(flags.in, false)
42+
translation = await luTranslator.translateLuObj(result, flags.translatekey, flags.tgtlang, flags.srclang, flags.translate_comments, flags.translate_link_text)
43+
result = {}
44+
Object.keys(translation).forEach(async idx => {
45+
result[flags.in][idx] = await luConverter.parseFile(translation[idx][0], false, undefined)
46+
})
4847
}
4948

5049
if (flags.out) {
51-
let languages = flags.tgtlang.split(',')
52-
await this.writeOutput(result, luFiles, isLu, languages, flags.out)
50+
await this.writeOutput(result, flags.out)
5351
} else {
5452
this.log(result)
5553
}
5654

5755
} catch (err) {
56+
if (err instanceof exception) {
57+
throw new CLIError(err.text)
58+
}
5859
throw err
5960
}
6061
}
6162

62-
private async getLuFiles(input: string | undefined, recurse = false): Promise<Array<any>> {
63-
let filesToParse = []
64-
65-
if (this.inputStat.isFile()) {
66-
filesToParse.push(input)
67-
return filesToParse
68-
}
69-
70-
if (!this.inputStat.isDirectory()) {
71-
throw new CLIError('Sorry, ' + input + ' is not a folder or does not exist')
72-
}
73-
74-
filesToParse = helpers.findLUFiles(input, recurse)
75-
76-
if (filesToParse.length === 0) {
77-
throw new CLIError('Sorry, no .lu files found in the specified folder.')
78-
}
79-
return filesToParse
80-
}
81-
82-
private async writeOutput(translatedObject: any, files: Array<string>, isLu: boolean, languages: Array<string>, out: string) {
63+
private async writeOutput(translatedObject: any, out: string) {
8364
let filePath = ''
8465
try {
85-
if (isLu) {
86-
let fileIndex = 0
87-
while (files.length > fileIndex) {
88-
let file = files[fileIndex++] + ''
89-
let lngIndex = 0
90-
while (languages.length > lngIndex) {
91-
let lg = languages[lngIndex++] + ''
92-
filePath = await this.generateNewFilePath(path.basename(file), lg, out)
93-
await fs.writeFile(filePath, translatedObject[path.basename(file)][lg], 'utf-8')
94-
}
66+
for (let file in translatedObject) {
67+
for (let lng in translatedObject[file]) {
68+
filePath = await fileHelper.generateNewTranslatedFilePath(file, lng, out)
69+
await fs.writeFile(filePath, translatedObject[path.basename(file)][lng], 'utf-8')
9570
}
96-
} else {
97-
await fs.writeFile(filePath, translatedObject, 'utf-8')
9871
}
9972
} catch (err) {
10073
throw new CLIError('Unable to write file - ' + filePath + ' Error: ' + err.message)
10174
}
102-
this.log('Successfully wrote translated model to ' + filePath)
103-
}
104-
105-
private async generateNewFilePath(fileName: string, translatedLanguage: string, output: string): Promise<string> {
106-
let outputStat = await fs.stat(output)
107-
if (outputStat.isFile()) {
108-
return path.join(process.cwd(), output)
109-
} else {
110-
let base = path.join(process.cwd(), output, translatedLanguage)
111-
await fs.mkdirp(base)
112-
return path.join(base, fileName)
113-
}
11475
}
11576
}

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

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {CLIError, Command, flags} from '@microsoft/bf-cli-command'
22
const exception = require('./../../../parser/lufile/classes/exception')
33
const fs = require('fs-extra')
44
const path = require('path')
5-
const helpers = require('./../../../parser/lufile/helpers')
5+
const file = require('./../../utils/filehelper')
66
const luConverter = require('./../../../parser/converters/qnatoqnajsonconverter')
77
const qnaConverter = require('./../../../parser/converters/qnajsontoqnaconverter')
88

@@ -19,21 +19,19 @@ export default class QnamakerConvert extends Command {
1919
name: flags.string({description: 'Name of the QnA KB'}),
2020
}
2121

22-
inputStat: any
23-
2422
async run() {
2523
try {
2624
const {flags} = this.parse(QnamakerConvert)
2725

2826
// Check if file or folder
2927
// If folder, only lu to luis is supported
30-
this.inputStat = await fs.stat(flags.in)
31-
let isQnA = !this.inputStat.isFile() ? true : path.extname(flags.in) === '.lu'
28+
let inputStat = await fs.stat(flags.in)
29+
let isQnA = !inputStat.isFile() ? true : path.extname(flags.in) === '.lu'
3230

3331
// Parse the object depending on the input
3432
let result: any
3533
if (isQnA) {
36-
let luFiles = await this.getLuFiles(flags.in, flags.recurse)
34+
let luFiles = await file.getLuFiles(flags.in, flags.recurse)
3735
result = await luConverter.parseQnaToJson(luFiles, false, flags.luis_culture)
3836
} else {
3937
result = await qnaConverter.parseQnAFileToLu(flags.in, flags.alterations, flags.sort)
@@ -68,33 +66,13 @@ export default class QnamakerConvert extends Command {
6866
}
6967
}
7068

71-
private async getLuFiles(input: string | undefined, recurse = false): Promise<Array<any>> {
72-
let filesToParse = []
73-
74-
if (this.inputStat.isFile()) {
75-
filesToParse.push(input)
76-
return filesToParse
77-
}
78-
79-
if (!this.inputStat.isDirectory()) {
80-
throw new CLIError('Sorry, ' + input + ' is not a folder or does not exist')
81-
}
82-
83-
filesToParse = helpers.findLUFiles(input, recurse)
84-
85-
if (filesToParse.length === 0) {
86-
throw new CLIError('Sorry, no .lu files found in the specified folder.')
87-
}
88-
return filesToParse
89-
}
90-
9169
private async writeOutput(convertedObject: any, flags: any, isQnA: boolean) {
92-
let filePath = await this.generateNewFilePath(flags.out, flags.in, isQnA, false)
70+
let filePath = await file.generateNewFilePath(flags.out, flags.in, isQnA)
9371
try {
9472
if (isQnA) {
9573
await fs.writeFile(filePath, JSON.stringify(convertedObject.finalQnAJSON, null, 2), 'utf-8')
9674
if (convertedObject.finalQnAAlterations) {
97-
let filePathAlterations = await this.generateNewFilePath(flags.out, flags.in, isQnA, true)
75+
let filePathAlterations = await file.generateNewFilePath(flags.out, flags.in, isQnA, 'alterations_')
9876
await fs.writeFile(filePathAlterations, JSON.stringify(convertedObject.finalQnAAlterations, null, 2), 'utf-8')
9977
}
10078
} else {
@@ -105,21 +83,4 @@ export default class QnamakerConvert extends Command {
10583
}
10684
this.log('Successfully wrote QnA model to ' + filePath)
10785
}
108-
109-
private async generateNewFilePath(outFileName: string, inputfile: string, isQnA: boolean, isAlterations: boolean): Promise<string> {
110-
let name = isAlterations ? 'alterations_' : ''
111-
let extension = path.extname(outFileName)
112-
if (extension === '.json' || extension === '.lu') {
113-
return path.join(process.cwd(), name + outFileName)
114-
}
115-
116-
let base = path.join(process.cwd(), outFileName)
117-
await fs.mkdirp(base)
118-
if (this.inputStat.isFile()) {
119-
name += path.basename(inputfile, path.extname(inputfile)) + (isQnA ? '.json' : '.lu')
120-
} else {
121-
name += isQnA ? 'qnafile.lu' : 'qna.json'
122-
}
123-
return path.join(base, name)
124-
}
12586
}

0 commit comments

Comments
 (0)