From 03a6ebc26faee5439848e83aa11d6be7a91586b4 Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Fri, 12 Jun 2020 16:12:56 +0800 Subject: [PATCH 1/7] support qna section CRUD --- packages/lu/package.json | 3 +- packages/lu/src/parser/lufile/luParser.js | 16 +++++ .../lu/src/parser/lufile/parseFileContents.js | 6 +- packages/lu/src/parser/lufile/qnaSection.js | 5 +- .../lu/test/parser/lufile/sectionapi.test.js | 64 +++++++++++++++++++ 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/packages/lu/package.json b/packages/lu/package.json index 4c15160f2..5bd48da4a 100644 --- a/packages/lu/package.json +++ b/packages/lu/package.json @@ -51,7 +51,8 @@ "lodash": "^4.17.15", "node-fetch": "~2.6.0", "semver": "^5.5.1", - "tslib": "^1.10.0" + "tslib": "^1.10.0", + "uuid": "^3.3.3" }, "devDependencies": { "@oclif/test": "^1.2.5", diff --git a/packages/lu/src/parser/lufile/luParser.js b/packages/lu/src/parser/lufile/luParser.js index e2ad2d063..9d2928b0c 100644 --- a/packages/lu/src/parser/lufile/luParser.js +++ b/packages/lu/src/parser/lufile/luParser.js @@ -324,6 +324,22 @@ class LUParser { if (section.SectionType === SectionType.NESTEDINTENTSECTION) { LUParser.extractIntentBody(section.SimpleIntentSections, originList.slice(0, stopLine).join(NEWLINE)) } + } else if (section.SectionType === SectionType.QNASECTION) { + const startLine = section.ParseTree.start.line - 1 + let stopLine + if (index + 1 < sections.length) { + stopLine = sections[index + 1].ParseTree.start.line - 1 + if (isNaN(startLine) || isNaN(stopLine) || startLine < 0 || startLine >= stopLine || originList.Length <= stopLine) { + throw new Error("index out of range.") + } + } else { + stopLine = originList.length + } + + const destList = originList.slice(startLine, stopLine) + section.Body = destList.join(NEWLINE) + section.StartLine = startLine + section.StopLine = stopLine - 1 } else { section.StartLine = section.ParseTree.start.line section.StopLine = section.ParseTree.stop.line - 1 diff --git a/packages/lu/src/parser/lufile/parseFileContents.js b/packages/lu/src/parser/lufile/parseFileContents.js index 5a4f93f90..a2a4d51fa 100644 --- a/packages/lu/src/parser/lufile/parseFileContents.js +++ b/packages/lu/src/parser/lufile/parseFileContents.js @@ -1817,8 +1817,8 @@ const parseAndHandleQnaSection = function (parsedContent, luResource) { let qnas = luResource.Sections.filter(s => s.SectionType === SectionType.QNASECTION); if (qnas && qnas.length > 0) { for (const qna of qnas) { - if (qna.Id) { - qna.Id = parseInt(qna.Id); + if (qna.QAPairId) { + qna.QAPairId = parseInt(qna.QAPairId); } let questions = qna.Questions; // detect if any question is a reference @@ -1844,7 +1844,7 @@ const parseAndHandleQnaSection = function (parsedContent, luResource) { context.prompts.push(new qnaPrompt(prompt.displayText, prompt.linkedQuestion, undefined, contextOnly, idx)); }) } - parsedContent.qnaJsonStructure.qnaList.push(new qnaListObj(qna.Id || 0, answer.trim(), qna.source, questions, metadata, context)); + parsedContent.qnaJsonStructure.qnaList.push(new qnaListObj(qna.QAPairId || 0, answer.trim(), qna.source, questions, metadata, context)); } } } diff --git a/packages/lu/src/parser/lufile/qnaSection.js b/packages/lu/src/parser/lufile/qnaSection.js index 27775f2f6..471a04b83 100644 --- a/packages/lu/src/parser/lufile/qnaSection.js +++ b/packages/lu/src/parser/lufile/qnaSection.js @@ -1,7 +1,7 @@ +const { v4: uuidv4 } = require('uuid'); const QnaSectionContext = require('./generated/LUFileParser').LUFileParser.QnaSectionContext; const LUSectionTypes = require('./../utils/enums/lusectiontypes'); const BuildDiagnostic = require('./diagnostic').BuildDiagnostic; -const helpers = require('../utils/helpers'); const QNA_GENERIC_SOURCE = "custom editorial"; class QnaSection { @@ -24,8 +24,9 @@ class QnaSection { this.prompts = result.promptDefinitions; this.promptsText = result.promptTextList; this.Errors = this.Errors.concat(result.errors); - this.Id = this.ExtractAssignedId(parseTree); + this.QAPairId = this.ExtractAssignedId(parseTree); this.source = this.ExtractSourceInfo(parseTree); + this.Id = uuidv4(); } ExtractSourceInfo(parseTree) { diff --git a/packages/lu/test/parser/lufile/sectionapi.test.js b/packages/lu/test/parser/lufile/sectionapi.test.js index 3a596414b..4dbf1d663 100644 --- a/packages/lu/test/parser/lufile/sectionapi.test.js +++ b/packages/lu/test/parser/lufile/sectionapi.test.js @@ -293,4 +293,68 @@ describe('Section CRUD tests for error import in utterances', () => { assert.equal(luresource.Sections[1].Name, 'Cancel') assert.equal(luresource.Sections[1].Body, '- cancel that') }); +}); + +describe('Section CRUD tests for qna', () => { + let luresource = undefined; + + let fileContent = +`# ? who is CEO of Microsoft +- Microsoft CEO + +\`\`\` +Satya Nadella +\`\`\``; + + let addedFileContent = +`# ? what about the weather of Seattle +- how about the weather of Seattle + +\`\`\` +warm and rainy +\`\`\`` + + let updatedFileConent = +`# ? who is CEO of Facebook +- Facebook CEO + +\`\`\` +Mark Zuckerberg +\`\`\``; + + it('add qna section test', () => { + luresource = luparser.parse(fileContent); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 1); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), fileContent); + + luresource = new SectionOperator(luresource).addSection(addedFileContent); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 2); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[1].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[1].Body.replace(/\r\n/g,"\n"), addedFileContent); + }); + + it('update qna section test', () => { + luresource = new SectionOperator(luresource).updateSection(luresource.Sections[0].Id, updatedFileConent); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 2); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[1].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), updatedFileConent); + }); + + it('delete qna section test', () => { + luresource = new SectionOperator(luresource).deleteSection(luresource.Sections[0].Id); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 1); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), addedFileContent); + }); }); \ No newline at end of file From 4c27f139c3bbfef2c6d0f5b519d68b21f881745b Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Fri, 12 Jun 2020 16:30:45 +0800 Subject: [PATCH 2/7] reduce dup code --- packages/lu/src/parser/lufile/luParser.js | 28 ++++++++--------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/lu/src/parser/lufile/luParser.js b/packages/lu/src/parser/lufile/luParser.js index 9d2928b0c..507bd9d29 100644 --- a/packages/lu/src/parser/lufile/luParser.js +++ b/packages/lu/src/parser/lufile/luParser.js @@ -304,7 +304,9 @@ class LUParser { sections.sort((a, b) => a.ParseTree.start.line - b.ParseTree.start.line) const originList = content.split(/\r?\n/) sections.forEach(function (section, index) { - if (section.SectionType === SectionType.SIMPLEINTENTSECTION || section.SectionType === SectionType.NESTEDINTENTSECTION) { + if (section.SectionType === SectionType.SIMPLEINTENTSECTION + || section.SectionType === SectionType.NESTEDINTENTSECTION + || section.SectionType === SectionType.QNASECTION) { const startLine = section.ParseTree.start.line - 1 let stopLine if (index + 1 < sections.length) { @@ -316,7 +318,13 @@ class LUParser { stopLine = originList.length } - const destList = originList.slice(startLine + 1, stopLine) + let destList + if (section.SectionType === SectionType.QNASECTION) { + destList = originList.slice(startLine, stopLine) + } else { + destList = originList.slice(startLine + 1, stopLine) + } + section.Body = destList.join(NEWLINE) section.StartLine = startLine section.StopLine = stopLine - 1 @@ -324,22 +332,6 @@ class LUParser { if (section.SectionType === SectionType.NESTEDINTENTSECTION) { LUParser.extractIntentBody(section.SimpleIntentSections, originList.slice(0, stopLine).join(NEWLINE)) } - } else if (section.SectionType === SectionType.QNASECTION) { - const startLine = section.ParseTree.start.line - 1 - let stopLine - if (index + 1 < sections.length) { - stopLine = sections[index + 1].ParseTree.start.line - 1 - if (isNaN(startLine) || isNaN(stopLine) || startLine < 0 || startLine >= stopLine || originList.Length <= stopLine) { - throw new Error("index out of range.") - } - } else { - stopLine = originList.length - } - - const destList = originList.slice(startLine, stopLine) - section.Body = destList.join(NEWLINE) - section.StartLine = startLine - section.StopLine = stopLine - 1 } else { section.StartLine = section.ParseTree.start.line section.StopLine = section.ParseTree.stop.line - 1 From d31f3394beb66798816400dd3f0c0ccae60cdbc9 Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Fri, 12 Jun 2020 17:26:11 +0800 Subject: [PATCH 3/7] change qna section Id to QAPairId --- packages/lu/src/parser/cross-train/crossTrainer.js | 4 ++-- packages/lu/src/parser/lufile/luParser.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/lu/src/parser/cross-train/crossTrainer.js b/packages/lu/src/parser/cross-train/crossTrainer.js index 53eded8bc..0ca769685 100644 --- a/packages/lu/src/parser/cross-train/crossTrainer.js +++ b/packages/lu/src/parser/cross-train/crossTrainer.js @@ -439,8 +439,8 @@ const qnaCrossTrainCore = function (luResource, qnaResource, fileName, interrupt qnaSectionContent += `> !# @qna.pair.source = ${qnaSection.source}${NEWLINE}${NEWLINE}` } - if (qnaSection.Id) { - qnaSectionContent += `${NEWLINE}${NEWLINE}` + if (qnaSection.QAPairId) { + qnaSectionContent += `${NEWLINE}${NEWLINE}` } qnaSectionContent += `# ? ${Array.from(new Set(qnaSection.Questions)).join(NEWLINE + '- ')}${NEWLINE}${NEWLINE}**Filters:**${NEWLINE}- ${qnaSection.FilterPairs.map(f => f.key + '=' + f.value).join(NEWLINE + '- ')}${NEWLINE}${NEWLINE}\`\`\`${NEWLINE}${qnaSection.Answer}${NEWLINE}\`\`\`` diff --git a/packages/lu/src/parser/lufile/luParser.js b/packages/lu/src/parser/lufile/luParser.js index 507bd9d29..435868b2e 100644 --- a/packages/lu/src/parser/lufile/luParser.js +++ b/packages/lu/src/parser/lufile/luParser.js @@ -124,7 +124,7 @@ class LUParser { })) } - this.extractIntentBody(sections, content) + this.extractSectionBody(sections, content) return new LUResource(sections, content, errors); } @@ -300,7 +300,7 @@ class LUParser { * @param {any[]} sections * @param {string} content */ - static extractIntentBody(sections, content) { + static extractSectionBody(sections, content) { sections.sort((a, b) => a.ParseTree.start.line - b.ParseTree.start.line) const originList = content.split(/\r?\n/) sections.forEach(function (section, index) { From 107e1ac491bfaa256cf08df3496b888c91f4c974 Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Fri, 12 Jun 2020 17:56:46 +0800 Subject: [PATCH 4/7] typo --- packages/lu/src/parser/lufile/luParser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lu/src/parser/lufile/luParser.js b/packages/lu/src/parser/lufile/luParser.js index 435868b2e..66797d8a7 100644 --- a/packages/lu/src/parser/lufile/luParser.js +++ b/packages/lu/src/parser/lufile/luParser.js @@ -330,7 +330,7 @@ class LUParser { section.StopLine = stopLine - 1 if (section.SectionType === SectionType.NESTEDINTENTSECTION) { - LUParser.extractIntentBody(section.SimpleIntentSections, originList.slice(0, stopLine).join(NEWLINE)) + LUParser.extractSectionBody(section.SimpleIntentSections, originList.slice(0, stopLine).join(NEWLINE)) } } else { section.StartLine = section.ParseTree.start.line From b56c7af3bfedf4aec32d978960d4bcfc1164ea01 Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Wed, 17 Jun 2020 11:47:03 +0800 Subject: [PATCH 5/7] fix RegExp not work in client env --- packages/lu/src/parser/lufile/qnaSection.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/lu/src/parser/lufile/qnaSection.js b/packages/lu/src/parser/lufile/qnaSection.js index 471a04b83..4f991e3b3 100644 --- a/packages/lu/src/parser/lufile/qnaSection.js +++ b/packages/lu/src/parser/lufile/qnaSection.js @@ -32,7 +32,7 @@ class QnaSection { ExtractSourceInfo(parseTree) { let srcAssignment = parseTree.qnaDefinition().qnaSourceInfo() if (srcAssignment) { - let srcRegExp = new RegExp(/^[ ]*\>[ ]*!#[ ]*@qna.pair.source[ ]*=[ ]*(?.*?)$/gmi); + let srcRegExp = /^[ ]*\>[ ]*!#[ ]*@qna.pair.source[ ]*=[ ]*(?.*?)$/gmi; let srcParsed = srcRegExp.exec(srcAssignment.getText().trim()); return srcParsed.groups.sourceInfo || QNA_GENERIC_SOURCE; } @@ -42,7 +42,7 @@ class QnaSection { ExtractAssignedId(parseTree) { let idAssignment = parseTree.qnaDefinition().qnaIdMark() if (idAssignment) { - let idTextRegExp = new RegExp(/^\.*?)[\"\'][ ]*>[ ]*\<\/a\>$/gmi); + let idTextRegExp = /^\.*?)[\"\'][ ]*>[ ]*\<\/a\>$/gmi; let idTextParsed = idTextRegExp.exec(idAssignment.getText().trim()); return idTextParsed.groups.idCaptured || undefined; } @@ -71,7 +71,7 @@ class QnaSection { let filterLineText = promptLine.getText().trim(); filterLineText = filterLineText.substr(1).trim(); promptTextList.push(filterLineText); - let promptConfigurationRegExp = new RegExp(/^\[(?.*?)]\([ ]*\#[ ]*[ ?]*(?.*?)\)[ ]*(?\`context-only\`)?.*?$/gmi); + let promptConfigurationRegExp = /^\[(?.*?)]\([ ]*\#[ ]*[ ?]*(?.*?)\)[ ]*(?\`context-only\`)?.*?$/gmi; let splitLine = promptConfigurationRegExp.exec(filterLineText); if (!splitLine) { errors.push(BuildDiagnostic({ From d2910612548cbbbc8796da2dece82e3556219918 Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Fri, 19 Jun 2020 13:29:00 +0800 Subject: [PATCH 6/7] add insertSection API --- packages/lu/package.json | 3 +- packages/lu/src/parser/lufile/luParser.js | 3 ++ packages/lu/src/parser/lufile/qnaSection.js | 2 - .../lu/src/parser/lufile/sectionOperator.js | 17 +++++++- .../lu/test/parser/lufile/sectionapi.test.js | 39 ++++++++++++++++++- 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/packages/lu/package.json b/packages/lu/package.json index 5bd48da4a..4c15160f2 100644 --- a/packages/lu/package.json +++ b/packages/lu/package.json @@ -51,8 +51,7 @@ "lodash": "^4.17.15", "node-fetch": "~2.6.0", "semver": "^5.5.1", - "tslib": "^1.10.0", - "uuid": "^3.3.3" + "tslib": "^1.10.0" }, "devDependencies": { "@oclif/test": "^1.2.5", diff --git a/packages/lu/src/parser/lufile/luParser.js b/packages/lu/src/parser/lufile/luParser.js index 66797d8a7..92cbd8ca0 100644 --- a/packages/lu/src/parser/lufile/luParser.js +++ b/packages/lu/src/parser/lufile/luParser.js @@ -303,6 +303,7 @@ class LUParser { static extractSectionBody(sections, content) { sections.sort((a, b) => a.ParseTree.start.line - b.ParseTree.start.line) const originList = content.split(/\r?\n/) + let qnaSectionIndex = 0 sections.forEach(function (section, index) { if (section.SectionType === SectionType.SIMPLEINTENTSECTION || section.SectionType === SectionType.NESTEDINTENTSECTION @@ -321,6 +322,8 @@ class LUParser { let destList if (section.SectionType === SectionType.QNASECTION) { destList = originList.slice(startLine, stopLine) + section.Id = qnaSectionIndex + qnaSectionIndex++ } else { destList = originList.slice(startLine + 1, stopLine) } diff --git a/packages/lu/src/parser/lufile/qnaSection.js b/packages/lu/src/parser/lufile/qnaSection.js index 4f991e3b3..ff35dc012 100644 --- a/packages/lu/src/parser/lufile/qnaSection.js +++ b/packages/lu/src/parser/lufile/qnaSection.js @@ -1,4 +1,3 @@ -const { v4: uuidv4 } = require('uuid'); const QnaSectionContext = require('./generated/LUFileParser').LUFileParser.QnaSectionContext; const LUSectionTypes = require('./../utils/enums/lusectiontypes'); const BuildDiagnostic = require('./diagnostic').BuildDiagnostic; @@ -26,7 +25,6 @@ class QnaSection { this.Errors = this.Errors.concat(result.errors); this.QAPairId = this.ExtractAssignedId(parseTree); this.source = this.ExtractSourceInfo(parseTree); - this.Id = uuidv4(); } ExtractSourceInfo(parseTree) { diff --git a/packages/lu/src/parser/lufile/sectionOperator.js b/packages/lu/src/parser/lufile/sectionOperator.js index 6793ff962..e3ae0c7f6 100644 --- a/packages/lu/src/parser/lufile/sectionOperator.js +++ b/packages/lu/src/parser/lufile/sectionOperator.js @@ -49,6 +49,21 @@ class SectionOperator { return luParser.parse(newContent); } + insertSection(id, sectionContent) { + sectionContent = helpers.sanitizeNewLines(sectionContent); + const section = this.Luresource.Sections.find(u => u.Id === id); + if (!section) { + return this.Luresource; + } + + const startLine = section.StartLine; + const newContent = this.replaceRangeContent(this.Luresource.Content, startLine, startLine - 1, sectionContent); + + const result = luParser.parse(newContent); + + return result; + } + replaceRangeContent(originString, startLine, stopLine, replaceString) { if (!originString) { @@ -57,7 +72,7 @@ class SectionOperator { const originList = originString.split(/\r?\n/); let destList = []; - if (isNaN(startLine) || isNaN(stopLine) || startLine < 0 || startLine > stopLine || originList.length <= stopLine) { + if (isNaN(startLine) || isNaN(stopLine) || startLine < 0 || startLine > stopLine + 1 || originList.length <= stopLine) { throw new Error("index out of range."); } diff --git a/packages/lu/test/parser/lufile/sectionapi.test.js b/packages/lu/test/parser/lufile/sectionapi.test.js index 4dbf1d663..afda7812a 100644 --- a/packages/lu/test/parser/lufile/sectionapi.test.js +++ b/packages/lu/test/parser/lufile/sectionapi.test.js @@ -322,6 +322,13 @@ warm and rainy Mark Zuckerberg \`\`\``; + let insertFileContent = +`# ? how to greet + +\`\`\` +hello +\`\`\`` + it('add qna section test', () => { luresource = luparser.parse(fileContent); @@ -349,12 +356,40 @@ Mark Zuckerberg assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), updatedFileConent); }); + it('insert qna section at begining test', () => { + luresource = new SectionOperator(luresource).insertSection(luresource.Sections[0].Id, insertFileContent); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 3); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[1].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[2].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), insertFileContent); + assert.equal(luresource.Sections[1].Body.replace(/\r\n/g,"\n"), updatedFileConent); + assert.equal(luresource.Sections[2].Body.replace(/\r\n/g,"\n"), addedFileContent); + }); + it('delete qna section test', () => { luresource = new SectionOperator(luresource).deleteSection(luresource.Sections[0].Id); assert.equal(luresource.Errors.length, 0); - assert.equal(luresource.Sections.length, 1); + assert.equal(luresource.Sections.length, 2); assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); - assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), addedFileContent); + assert.equal(luresource.Sections[1].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), updatedFileConent); + assert.equal(luresource.Sections[1].Body.replace(/\r\n/g,"\n"), addedFileContent); + }); + + it('insert qna section at middle test', () => { + luresource = new SectionOperator(luresource).insertSection(luresource.Sections[1].Id, insertFileContent); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 3); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[1].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[2].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), updatedFileConent); + assert.equal(luresource.Sections[1].Body.replace(/\r\n/g,"\n"), insertFileContent); + assert.equal(luresource.Sections[2].Body.replace(/\r\n/g,"\n"), addedFileContent); }); }); \ No newline at end of file From 525149db6e42fe70f4b9b5225a27a407119b1f79 Mon Sep 17 00:00:00 2001 From: Fei Chen Date: Tue, 23 Jun 2020 10:50:25 +0800 Subject: [PATCH 7/7] support insert at an empty file --- packages/lu/src/parser/lufile/sectionOperator.js | 9 ++------- packages/lu/test/parser/lufile/sectionapi.test.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/lu/src/parser/lufile/sectionOperator.js b/packages/lu/src/parser/lufile/sectionOperator.js index e3ae0c7f6..559e5ee9c 100644 --- a/packages/lu/src/parser/lufile/sectionOperator.js +++ b/packages/lu/src/parser/lufile/sectionOperator.js @@ -52,11 +52,11 @@ class SectionOperator { insertSection(id, sectionContent) { sectionContent = helpers.sanitizeNewLines(sectionContent); const section = this.Luresource.Sections.find(u => u.Id === id); - if (!section) { + if (!section && this.Luresource.Sections.length > 0 ) { return this.Luresource; } - const startLine = section.StartLine; + const startLine = section ? section.StartLine : 0; const newContent = this.replaceRangeContent(this.Luresource.Content, startLine, startLine - 1, sectionContent); const result = luParser.parse(newContent); @@ -65,11 +65,6 @@ class SectionOperator { } replaceRangeContent(originString, startLine, stopLine, replaceString) { - - if (!originString) { - throw new Error('replace content with error parameters.'); - } - const originList = originString.split(/\r?\n/); let destList = []; if (isNaN(startLine) || isNaN(stopLine) || startLine < 0 || startLine > stopLine + 1 || originList.length <= stopLine) { diff --git a/packages/lu/test/parser/lufile/sectionapi.test.js b/packages/lu/test/parser/lufile/sectionapi.test.js index afda7812a..239fa89f7 100644 --- a/packages/lu/test/parser/lufile/sectionapi.test.js +++ b/packages/lu/test/parser/lufile/sectionapi.test.js @@ -392,4 +392,14 @@ hello assert.equal(luresource.Sections[1].Body.replace(/\r\n/g,"\n"), insertFileContent); assert.equal(luresource.Sections[2].Body.replace(/\r\n/g,"\n"), addedFileContent); }); + + it('insert qna section at empty file', () => { + luresource = luparser.parse(''); + luresource = new SectionOperator(luresource).insertSection(0, insertFileContent); + + assert.equal(luresource.Errors.length, 0); + assert.equal(luresource.Sections.length, 1); + assert.equal(luresource.Sections[0].SectionType, LUSectionTypes.QNASECTION); + assert.equal(luresource.Sections[0].Body.replace(/\r\n/g,"\n"), insertFileContent + '\n'); + }); }); \ No newline at end of file