h1 {
- margin-top: 0;
- }
-`;
-
export const settingsEditor = css`
flex: 1;
height: 500px;
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx
index ca53a4d3a0..38f1927429 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx
@@ -5,6 +5,7 @@ import { useRecoilState } from 'recoil';
import { LuIntentSection, LuFile } from '@bfc/shared';
import { useRecoilValue } from 'recoil';
import { act } from '@bfc/test-utils/lib/hooks';
+import { luUtil } from '@bfc/indexers';
import { renderRecoilHook } from '../../../../__tests__/testUtils';
import { luFilesState } from '../../atoms';
@@ -22,12 +23,13 @@ jest.mock('../../parsers/luWorker', () => {
removeIntents: require('@bfc/indexers/lib/utils/luUtil').removeIntents,
};
});
-const luFiles = [
- {
- id: 'common.en-us',
- content: `\r\n# Hello\r\n-hi`,
- },
-] as LuFile[];
+
+const file1 = {
+ id: 'common.en-us',
+ content: `\r\n# Hello\r\n-hi`,
+};
+
+const luFiles = [luUtil.parse(file1.id, file1.content)] as LuFile[];
const getLuIntent = (Name, Body): LuIntentSection =>
({
@@ -96,7 +98,7 @@ describe('Lu dispatcher', () => {
expect(renderedComponent.current.luFiles[0].content).toMatch(/-IntentValue/);
});
- it('should remove a lg template', async () => {
+ it('should remove a lu intent', async () => {
await act(async () => {
await dispatcher.removeLuIntent({
id: luFiles[0].id,
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/lg.ts b/Composer/packages/client/src/recoilModel/dispatchers/lg.ts
index 9e031e21b7..9c24d56c08 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/lg.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/lg.ts
@@ -4,6 +4,7 @@
import { LgTemplate, LgFile, importResolverGenerator } from '@bfc/shared';
import { useRecoilCallback, CallbackInterface } from 'recoil';
import differenceBy from 'lodash/differenceBy';
+import formatMessage from 'format-message';
import { getBaseName, getExtension } from '../../utils/fileUtil';
@@ -20,13 +21,13 @@ const initialBody = '- ';
export const updateLgFileState = async (
callbackHelpers: CallbackInterface,
- { id, content }: { id: string; content: string }
+ { id, content, updatedFile }: { id: string; content: string; updatedFile?: LgFile }
) => {
const { set, snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesState);
const dialogId = getBaseName(id);
const locale = getExtension(id);
- const updatedLgFile = (await LgWorker.parse(id, content, lgFiles)) as LgFile;
+ const updatedLgFile = updatedFile || ((await LgWorker.parse(id, content, lgFiles)) as LgFile);
const originLgFile = lgFiles.find((file) => id === file.id);
const sameIdOtherLocaleFiles = lgFiles.filter((file) => {
const fileDialogId = getBaseName(file.id);
@@ -35,7 +36,7 @@ export const updateLgFileState = async (
});
if (!originLgFile) {
- throw new Error('origin lg file not found in store');
+ throw new Error(formatMessage('origin lg file not found in store'));
}
const changes: LgFile[] = [updatedLgFile];
@@ -58,10 +59,9 @@ export const updateLgFileState = async (
if (onlyAdds || onlyDeletes) {
for (const file of sameIdOtherLocaleFiles) {
const lgImportResolver = importResolverGenerator(lgFiles, '.lg', getExtension(file.id));
- let newLgFile = lgUtil.addTemplates(file.id, file.content, addedTemplates, lgImportResolver);
+ let newLgFile = lgUtil.addTemplates(file, addedTemplates, lgImportResolver);
newLgFile = lgUtil.removeTemplates(
- file.id,
- newLgFile.content,
+ newLgFile,
deletedTemplates.map(({ name }) => name),
lgImportResolver
);
@@ -92,7 +92,7 @@ export const createLgFileState = async (
const { languages } = await snapshot.getPromise(settingsState);
const createdLgId = `${id}.${locale}`;
if (lgFiles.find((lg) => lg.id === createdLgId)) {
- throw new Error('lg file already exist');
+ throw new Error(formatMessage('lg file already exist'));
}
// slot with common.lg import
let lgInitialContent = '';
@@ -101,7 +101,7 @@ export const createLgFileState = async (
lgInitialContent = `[import](common.lg)`;
}
content = [lgInitialContent, content].join('\n');
- const createdLgFile = (await LgWorker.parse(createdLgId, content, lgFiles)) as LgFile;
+ const createdLgFile = lgUtil.parse(createdLgId, content, lgFiles);
const changes: LgFile[] = [];
// copy to other locales
@@ -155,9 +155,12 @@ export const lgDispatcher = () => {
}) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesState);
- let content = lgFiles.find((file) => file.id === id)?.content ?? '';
- content = lgUtil.updateTemplate(id, content, templateName, template, lgFileResolver(lgFiles)).content;
- await updateLgFileState(callbackHelpers, { id, content });
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) {
+ throw new Error(formatMessage('lg file {id} does not exist.', { id }));
+ }
+ const updatedFile = lgUtil.updateTemplate(lgFile, templateName, template, lgFileResolver(lgFiles));
+ await updateLgFileState(callbackHelpers, { id, content: updatedFile.content, updatedFile });
}
);
@@ -165,9 +168,13 @@ export const lgDispatcher = () => {
(callbackHelpers: CallbackInterface) => async ({ id, template }: { id: string; template: LgTemplate }) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesState);
- let content = lgFiles.find((file) => file.id === id)?.content ?? '';
- content = lgUtil.addTemplate(id, content, template, lgFileResolver(lgFiles)).content;
- await updateLgFileState(callbackHelpers, { id, content });
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) {
+ throw new Error(formatMessage('lg file {id} does not exist.', { id }));
+ }
+
+ const updatedFile = lgUtil.addTemplate(lgFile, template, lgFileResolver(lgFiles));
+ await updateLgFileState(callbackHelpers, { id, updatedFile, content: updatedFile.content });
}
);
@@ -175,9 +182,13 @@ export const lgDispatcher = () => {
(callbackHelpers: CallbackInterface) => async ({ id, templateName }: { id: string; templateName: string }) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesState);
- let content = lgFiles.find((file) => file.id === id)?.content ?? '';
- content = lgUtil.removeTemplate(id, content, templateName, lgFileResolver(lgFiles)).content;
- await updateLgFileState(callbackHelpers, { id, content });
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) {
+ throw new Error(formatMessage('lg file {id} does not exist.', { id }));
+ }
+
+ const updatedFile = lgUtil.removeTemplate(lgFile, templateName, lgFileResolver(lgFiles));
+ await updateLgFileState(callbackHelpers, { id, updatedFile, content: updatedFile.content });
}
);
@@ -185,9 +196,12 @@ export const lgDispatcher = () => {
(callbackHelpers: CallbackInterface) => async ({ id, templateNames }: { id: string; templateNames: string[] }) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesState);
- let content = lgFiles.find((file) => file.id === id)?.content ?? '';
- content = lgUtil.removeTemplates(id, content, templateNames, lgFileResolver(lgFiles)).content;
- await updateLgFileState(callbackHelpers, { id, content });
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) {
+ throw new Error(formatMessage('lg file {id} does not exist.', { id }));
+ }
+ const updatedFile = lgUtil.removeTemplates(lgFile, templateNames, lgFileResolver(lgFiles));
+ await updateLgFileState(callbackHelpers, { id, updatedFile, content: updatedFile.content });
}
);
@@ -203,9 +217,12 @@ export const lgDispatcher = () => {
}) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesState);
- let content = lgFiles.find((file) => file.id === id)?.content ?? '';
- content = lgUtil.copyTemplate(id, content, fromTemplateName, toTemplateName, lgFileResolver(lgFiles)).content;
- await updateLgFileState(callbackHelpers, { id, content });
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) {
+ throw new Error(formatMessage('lg file {id} does not exist.', { id }));
+ }
+ const updatedFile = lgUtil.copyTemplate(lgFile, fromTemplateName, toTemplateName, lgFileResolver(lgFiles));
+ await updateLgFileState(callbackHelpers, { id, updatedFile, content: updatedFile.content });
}
);
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/lu.ts b/Composer/packages/client/src/recoilModel/dispatchers/lu.ts
index 97fd9f1846..d21c1e4ccf 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/lu.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/lu.ts
@@ -4,10 +4,12 @@
import { LuFile, LuIntentSection } from '@bfc/shared';
import { useRecoilCallback, CallbackInterface } from 'recoil';
import differenceBy from 'lodash/differenceBy';
+import formatMessage from 'format-message';
+import luWorker from '../parsers/luWorker';
import { getBaseName, getExtension } from '../../utils/fileUtil';
+import * as luUtil from '../../utils/luUtil';
import luFileStatusStorage from '../../utils/luFileStatusStorage';
-import luWorker from '../parsers/luWorker';
import { luFilesState, projectIdState, localeState, settingsState } from '../atoms/botState';
const intentIsNotEmpty = ({ Name, Body }) => {
@@ -18,7 +20,7 @@ const initialBody = '- ';
export const updateLuFileState = async (
callbackHelpers: CallbackInterface,
- { id, content }: { id: string; content: string }
+ { id, content, updatedFile }: { id: string; content: string; updatedFile?: LuFile }
) => {
const { set, snapshot } = callbackHelpers;
const luFiles = await snapshot.getPromise(luFilesState);
@@ -26,7 +28,7 @@ export const updateLuFileState = async (
const dialogId = getBaseName(id);
const locale = getExtension(id);
- const updatedLuFile = (await luWorker.parse(id, content)) as LuFile;
+ const updatedLuFile = updatedFile || ((await luWorker.parse(id, content)) as LuFile); // if exist updated luFile, do not parse again.
const originLuFile = luFiles.find((file) => id === file.id);
const sameIdOtherLocaleFiles = luFiles.filter((file) => {
const fileDialogId = getBaseName(file.id);
@@ -35,7 +37,7 @@ export const updateLuFileState = async (
});
if (!originLuFile) {
- throw new Error('origin lu file not found in store');
+ throw new Error(formatMessage('origin lu file not found in store'));
}
const changes: LuFile[] = [updatedLuFile];
@@ -53,13 +55,12 @@ export const updateLuFileState = async (
const onlyDeletes = !addedIntents.length && deletedIntents.length;
// sync add/remove intents
if (onlyAdds || onlyDeletes) {
- for (const { id, content } of sameIdOtherLocaleFiles) {
- let newContent: string = (await luWorker.addIntents(content, addedIntents)) as string;
- newContent = (await luWorker.removeIntents(
- newContent,
+ for (const item of sameIdOtherLocaleFiles) {
+ let newLuFile = luUtil.addIntents(item, addedIntents);
+ newLuFile = luUtil.removeIntents(
+ newLuFile,
deletedIntents.map(({ Name }) => Name)
- )) as string;
- const newLuFile = (await luWorker.parse(id, newContent)) as LuFile;
+ );
changes.push(newLuFile);
}
}
@@ -89,7 +90,7 @@ export const createLuFileState = async (
const locale = await snapshot.getPromise(localeState);
const { languages } = await snapshot.getPromise(settingsState);
const createdLuId = `${id}.${locale}`;
- const createdLuFile = (await luWorker.parse(id, content)) as LuFile;
+ const createdLuFile = (await luUtil.parse(id, content)) as LuFile;
if (luFiles.find((lu) => lu.id === createdLuId)) {
throw new Error('lu file already exist');
}
@@ -150,8 +151,8 @@ export const luDispatcher = () => {
const luFiles = await callbackHelpers.snapshot.getPromise(luFilesState);
const file = luFiles.find((temp) => temp.id === id);
if (!file) return;
- const content = (await luWorker.updateIntent(file.content, intentName, intent)) as string;
- await updateLuFileState(callbackHelpers, { id: file.id, content });
+ const updatedFile = luUtil.updateIntent(file, intentName, intent);
+ await updateLuFileState(callbackHelpers, { id: file.id, updatedFile, content: updatedFile.content });
}
);
@@ -160,8 +161,8 @@ export const luDispatcher = () => {
const luFiles = await callbackHelpers.snapshot.getPromise(luFilesState);
const file = luFiles.find((temp) => temp.id === id);
if (!file) return;
- const content = (await luWorker.addIntent(file.content, intent)) as string;
- await updateLuFileState(callbackHelpers, { id: file.id, content });
+ const updatedFile = luUtil.addIntent(file, intent);
+ await updateLuFileState(callbackHelpers, { id: file.id, updatedFile, content: updatedFile.content });
}
);
@@ -170,8 +171,8 @@ export const luDispatcher = () => {
const luFiles = await callbackHelpers.snapshot.getPromise(luFilesState);
const file = luFiles.find((temp) => temp.id === id);
if (!file) return;
- const content = (await luWorker.removeIntent(file.content, intentName)) as string;
- await updateLuFileState(callbackHelpers, { id: file.id, content });
+ const updatedFile = luUtil.removeIntent(file, intentName);
+ await updateLuFileState(callbackHelpers, { id: file.id, updatedFile, content: updatedFile.content });
}
);
diff --git a/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts b/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts
index c540913e01..2d980dcda8 100644
--- a/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts
@@ -28,7 +28,7 @@ const lgFiles = [
describe('test lg worker', () => {
it('get expected parse result', async () => {
const result: any = await lgWorker.parse('common.en-us', `\r\n# Hello\r\n-hi`, lgFiles);
- const expected = [{ body: '-hi', name: 'Hello', parameters: [], range: { endLineNumber: 0, startLineNumber: 0 } }];
+ const expected = [{ body: '-hi', name: 'Hello', parameters: [], range: { endLineNumber: 3, startLineNumber: 2 } }];
expect(result.templates).toMatchObject(expected);
});
});
diff --git a/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts b/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts
index 70dba60d7d..abe759eda7 100644
--- a/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import { LuIntentSection } from '@bfc/shared';
-
import luWorker from '../luWorker';
jest.mock('./../workers/luParser.worker.ts', () => {
@@ -18,12 +16,6 @@ jest.mock('./../workers/luParser.worker.ts', () => {
return Test;
});
-const getLuIntent = (Name, Body): LuIntentSection =>
- ({
- Name,
- Body,
- } as LuIntentSection);
-
describe('test lu worker', () => {
it('get expected parse result', async () => {
const content = `# Hello
@@ -49,41 +41,4 @@ hi
expect(diagnostics[0].range.end.line).toEqual(2);
expect(diagnostics[0].range.end.character).toEqual(2);
});
-
- it('should add an intent', async () => {
- const content = `# Greeting
- hi
- - hello
-
- @ simple friendsName
-
- `;
- const result: any = await luWorker.addIntent(content, getLuIntent('Hello', '-IntentValue'));
- expect(result).toContain('-IntentValue');
- });
-
- it('should remove an intent', async () => {
- const content = `# Greeting
- hi
- - hello
-
- @ simple friendsName
-
- `;
- const result: any = await luWorker.removeIntent(content, 'Greeting');
- expect(result).not.toContain('- hello');
- });
-
- it('should update an intent', async () => {
- const content = `# Greeting
- hi
- - hello
-
- @ simple friendsName
-
- `;
- const result: any = await luWorker.updateIntent(content, 'Greeting', getLuIntent('Greeting', '-IntentValue'));
- expect(result).not.toContain('- hello');
- expect(result).toContain('-IntentValue');
- });
});
diff --git a/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts b/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts
index cbcb1905f9..e5be382440 100644
--- a/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts
@@ -76,37 +76,6 @@ export const handleMessage = (msg: LgMessageEvent) => {
payload = { id, content, templates, diagnostics };
break;
}
- case LgActionType.AddTemplate: {
- const { id, content, template } = msg.payload;
- payload = lgUtil.addTemplate(id, content, template);
- break;
- }
- case LgActionType.AddTemplates: {
- const { id, content, templates } = msg.payload;
- payload = lgUtil.addTemplates(id, content, templates);
- break;
- }
- case LgActionType.UpdateTemplate: {
- const { id, content, templateName, template } = msg.payload;
- lgUtil.checkSingleLgTemplate(template);
- payload = lgUtil.updateTemplate(id, content, templateName, template);
- break;
- }
- case LgActionType.RemoveTemplate: {
- const { id, content, templateName } = msg.payload;
- payload = lgUtil.removeTemplate(id, content, templateName);
- break;
- }
- case LgActionType.RemoveAllTemplates: {
- const { id, content, templateNames } = msg.payload;
- payload = lgUtil.removeTemplates(id, content, templateNames);
- break;
- }
- case LgActionType.CopyTemplate: {
- const { id, content, toTemplateName, fromTemplateName } = msg.payload;
- payload = lgUtil.copyTemplate(id, content, fromTemplateName, toTemplateName);
- break;
- }
}
return payload;
};
diff --git a/Composer/packages/client/src/recoilModel/parsers/workers/luParser.worker.ts b/Composer/packages/client/src/recoilModel/parsers/workers/luParser.worker.ts
index cc9d7b3d7d..fd87c3c569 100644
--- a/Composer/packages/client/src/recoilModel/parsers/workers/luParser.worker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/workers/luParser.worker.ts
@@ -8,33 +8,13 @@ const ctx: Worker = self as any;
export const handleMessage = (msg) => {
const { type, payload } = msg.data;
- const { content, id, intentName, intentNames, intent, intents } = payload;
+ const { content, id } = payload;
let result: any = null;
switch (type) {
case LuActionType.Parse: {
result = luUtil.parse(id, content);
break;
}
- case LuActionType.AddIntent: {
- result = luUtil.addIntent(content, intent);
- break;
- }
- case LuActionType.AddIntents: {
- result = luUtil.addIntents(content, intents);
- break;
- }
- case LuActionType.UpdateIntent: {
- result = luUtil.updateIntent(content, intentName, intent || null);
- break;
- }
- case LuActionType.RemoveIntent: {
- result = luUtil.removeIntent(content, intentName);
- break;
- }
- case LuActionType.RemoveIntents: {
- result = luUtil.removeIntents(content, intentNames);
- break;
- }
}
return result;
};
diff --git a/Composer/packages/client/src/utils/dialogUtil.ts b/Composer/packages/client/src/utils/dialogUtil.ts
index d433cbad00..50c116dee7 100644
--- a/Composer/packages/client/src/utils/dialogUtil.ts
+++ b/Composer/packages/client/src/utils/dialogUtil.ts
@@ -72,7 +72,11 @@ function updateTriggerActionsAttributes(trigger, extraTriggerAttributes) {
t.actions[0].activity = `$\{SendActivity_${lgTemplateId}()}`;
}
if (t.$kind === SDKKinds.OnChooseIntent) {
- t.actions[1].prompt = `$\{ChoiceInput_Prompt_${lgTemplateId}}`;
+ //t.actions[1].prompt = `$\{ChoiceInput_Prompt_${lgTemplateId}}`;
+ for (const key in extraTriggerAttributes) {
+ set(t, key, extraTriggerAttributes[key]);
+ console.log(get(t, key, ''));
+ }
}
return t;
}
diff --git a/Composer/packages/electron-server/__tests__/appMenu.test.ts b/Composer/packages/electron-server/__tests__/appMenu.test.ts
index 7d61261100..3227f04f96 100644
--- a/Composer/packages/electron-server/__tests__/appMenu.test.ts
+++ b/Composer/packages/electron-server/__tests__/appMenu.test.ts
@@ -40,7 +40,7 @@ describe('App menu', () => {
// Edit
expect(menuTemplate[1].label).toBe('Edit');
- expect(menuTemplate[1].submenu.length).toBe(9);
+ expect(menuTemplate[1].submenu.length).toBe(8);
// View
expect(menuTemplate[2].label).toBe('View');
@@ -75,7 +75,7 @@ describe('App menu', () => {
// Edit
expect(menuTemplate[2].label).toBe('Edit');
- expect(menuTemplate[2].submenu.length).toBe(9);
+ expect(menuTemplate[2].submenu.length).toBe(8);
// View
expect(menuTemplate[3].label).toBe('View');
diff --git a/Composer/packages/electron-server/src/appMenu.ts b/Composer/packages/electron-server/src/appMenu.ts
index e61e6d7a70..f6e877c441 100644
--- a/Composer/packages/electron-server/src/appMenu.ts
+++ b/Composer/packages/electron-server/src/appMenu.ts
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import { app, dialog, Menu, MenuItemConstructorOptions, shell } from 'electron';
+import { app, dialog, Menu, MenuItemConstructorOptions, shell, ipcMain } from 'electron';
import { isMac } from './utility/platform';
import { AppUpdater } from './appUpdater';
@@ -29,7 +29,6 @@ function getAppMenu(): MenuItemConstructorOptions[] {
function getRestOfEditMenu(): MenuItemConstructorOptions[] {
if (isMac()) {
return [
- { role: 'delete' },
{ type: 'separator' },
{
label: 'Speech',
@@ -37,7 +36,7 @@ function getRestOfEditMenu(): MenuItemConstructorOptions[] {
},
];
}
- return [{ role: 'delete' }, { type: 'separator' }, { role: 'selectAll' }];
+ return [{ type: 'separator' }, { role: 'selectAll' }];
}
function getRestOfWindowMenu(): MenuItemConstructorOptions[] {
@@ -47,7 +46,14 @@ function getRestOfWindowMenu(): MenuItemConstructorOptions[] {
return [{ role: 'close' }];
}
-export function initAppMenu() {
+export function initAppMenu(win?: Electron.BrowserWindow) {
+ // delegate menu events to Renderer process (Composer web app)
+ const handleMenuEvents = (menuEventName: string) => {
+ if (win) {
+ win.webContents.send('electron-menu-clicked', { label: menuEventName });
+ }
+ };
+
const template: MenuItemConstructorOptions[] = [
// App (Mac)
...getAppMenu(),
@@ -60,12 +66,25 @@ export function initAppMenu() {
{
label: 'Edit',
submenu: [
- { role: 'undo' },
- { role: 'redo' },
+ // NOTE: Avoid using builtin `role`, it won't override the click handler.
+ { id: 'Undo', label: 'Undo', accelerator: 'CmdOrCtrl+Z', click: () => handleMenuEvents('undo') },
+ { id: 'Redo', label: 'Redo', accelerator: 'CmdOrCtrl+Shift+Z', click: () => handleMenuEvents('redo') },
{ type: 'separator' },
- { role: 'cut' },
- { role: 'copy' },
- { role: 'paste' },
+ { id: 'Cut', label: 'Cut', enabled: false, accelerator: 'CmdOrCtrl+X', click: () => handleMenuEvents('cut') },
+ {
+ id: 'Copy',
+ label: 'Copy',
+ enabled: false,
+ accelerator: 'CmdOrCtrl+C',
+ click: () => handleMenuEvents('copy'),
+ },
+ {
+ id: 'Delete',
+ label: 'Delete',
+ enabled: false,
+ accelerator: 'Delete',
+ click: () => handleMenuEvents('delete'),
+ },
...getRestOfEditMenu(),
],
},
@@ -161,4 +180,15 @@ export function initAppMenu() {
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
+
+ // Let menu enable/disable status reflect action selection states.
+ ipcMain &&
+ ipcMain.on &&
+ ipcMain.on('composer-state-change', (e, state) => {
+ const actionSelected = !!state.actionSelected;
+ ['Cut', 'Copy', 'Delete'].forEach((id) => {
+ menu.getMenuItemById(id).enabled = actionSelected;
+ });
+ Menu.setApplicationMenu(menu);
+ });
}
diff --git a/Composer/packages/electron-server/src/main.ts b/Composer/packages/electron-server/src/main.ts
index 79374bb772..4082227967 100644
--- a/Composer/packages/electron-server/src/main.ts
+++ b/Composer/packages/electron-server/src/main.ts
@@ -131,8 +131,8 @@ async function loadServer() {
async function main() {
log('Rendering application...');
- initAppMenu();
const mainWindow = ElectronWindow.getInstance().browserWindow;
+ initAppMenu(mainWindow);
if (mainWindow) {
if (process.env.COMPOSER_DEV_TOOLS) {
mainWindow.webContents.openDevTools();
diff --git a/Composer/packages/extensions/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts b/Composer/packages/extensions/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts
index bbfa51d423..8739daa91a 100644
--- a/Composer/packages/extensions/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts
+++ b/Composer/packages/extensions/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import { DialogUtils, SDKKinds, ShellApi } from '@bfc/shared';
+import { DialogUtils, SDKKinds, ShellApi, registerEditorAPI } from '@bfc/shared';
import get from 'lodash/get';
import { useDialogEditApi, useDialogApi, useActionApi } from '@bfc/extension';
@@ -311,13 +311,14 @@ export const useEditorEventApi = (
return handler(eventData);
};
- // HACK: use global handler before we solve iframe state sync problem
- (window as any).copySelection = () => handleEditorEvent(NodeEventTypes.CopySelection);
- (window as any).cutSelection = () => handleEditorEvent(NodeEventTypes.CutSelection);
- (window as any).moveSelection = () => handleEditorEvent(NodeEventTypes.MoveSelection);
- (window as any).deleteSelection = () => handleEditorEvent(NodeEventTypes.DeleteSelection);
- (window as any).disableSelection = () => handleEditorEvent(NodeEventTypes.DisableSelection);
- (window as any).enableSelection = () => handleEditorEvent(NodeEventTypes.EnableSelection);
+ registerEditorAPI('Actions', {
+ CopySelection: () => handleEditorEvent(NodeEventTypes.CopySelection),
+ CutSelection: () => handleEditorEvent(NodeEventTypes.CutSelection),
+ MoveSelection: () => handleEditorEvent(NodeEventTypes.MoveSelection),
+ DeleteSelection: () => handleEditorEvent(NodeEventTypes.DeleteSelection),
+ DisableSelection: () => handleEditorEvent(NodeEventTypes.DisableSelection),
+ EnableSelection: () => handleEditorEvent(NodeEventTypes.EnableSelection),
+ });
return {
handleEditorEvent,
diff --git a/Composer/packages/lib/indexers/__tests__/lgUtil.test.ts b/Composer/packages/lib/indexers/__tests__/lgUtil.test.ts
index 662b31dae3..36f278ea31 100644
--- a/Composer/packages/lib/indexers/__tests__/lgUtil.test.ts
+++ b/Composer/packages/lib/indexers/__tests__/lgUtil.test.ts
@@ -3,9 +3,41 @@
import { Templates } from 'botbuilder-lg';
-import { updateTemplate, addTemplate, checkTemplate, removeTemplate, extractOptionByKey } from '../src/utils/lgUtil';
+import {
+ updateTemplate,
+ addTemplate,
+ checkTemplate,
+ removeTemplate,
+ extractOptionByKey,
+ parse,
+} from '../src/utils/lgUtil';
describe('update lg template', () => {
+ it('should parse lg file', () => {
+ const content = `# Exit
+-Thanks for using todo bot.
+
+# Greeting
+-What's up bro`;
+
+ const templates = parse('a.lg', content, []).templates;
+ expect(templates.length).toEqual(2);
+ expect(templates[0].name).toEqual('Exit');
+ expect(templates[0].body).toContain('-Thanks for using todo bot.');
+ expect(templates[0].parameters).toEqual([]);
+ expect(templates[0].range).toEqual({
+ startLineNumber: 1,
+ endLineNumber: 3,
+ });
+ expect(templates[1].name).toEqual('Greeting');
+ expect(templates[1].body).toContain(`-What's up bro`);
+ expect(templates[1].parameters).toEqual([]);
+ expect(templates[1].range).toEqual({
+ startLineNumber: 4,
+ endLineNumber: 5,
+ });
+ });
+
it('should update lg template', () => {
const content = `# Exit
-Thanks for using todo bot.
@@ -13,9 +45,10 @@ describe('update lg template', () => {
# Greeting
-What's up bro`;
+ const lgFile = parse('a.lg', content, []);
const template = { name: 'Exit', parameters: [], body: '-Bye' };
- const newContent = updateTemplate(content, 'Exit', template);
- const templates = Templates.parseText(newContent).toArray();
+ const updatedLgFile = updateTemplate(lgFile, 'Exit', template);
+ const templates = Templates.parseText(updatedLgFile.content).toArray();
expect(templates.length).toEqual(2);
expect(templates[0].name).toEqual('Exit');
expect(templates[0].body).toEqual('-Bye');
@@ -27,12 +60,13 @@ describe('update lg template', () => {
# Greeting
-What's up bro`;
+ const lgFile = parse('a.lg', content, []);
const templates0 = Templates.parseText(content).toArray();
expect(templates0.length).toEqual(2);
const template = { name: 'Exit', parameters: [], body: '-Bye' };
- const newContent = updateTemplate(content, 'Exit', template);
- const templates = Templates.parseText(newContent).toArray();
+ const updatedLgFile = updateTemplate(lgFile, 'Exit', template);
+ const templates = Templates.parseText(updatedLgFile.content).toArray();
expect(templates.length).toEqual(2);
expect(templates[0].name).toEqual('Exit');
expect(templates[0].body).toEqual('-Bye');
@@ -46,9 +80,10 @@ describe('add lg template', () => {
# Greeting
-What's up bro`;
+ const lgFile = parse('a.lg', content, []);
const template = { name: 'Hi', parameters: [], body: '-hello' };
- const newContent = addTemplate(content, template);
- const templates = Templates.parseText(newContent).toArray();
+ const updatedLgFile = addTemplate(lgFile, template);
+ const templates = Templates.parseText(updatedLgFile.content).toArray();
expect(templates.length).toEqual(3);
expect(templates[0].name).toEqual('Exit');
expect(templates[1].name).toEqual('Greeting');
@@ -63,8 +98,9 @@ describe('remove lg template', () => {
# Greeting
-What's up bro`;
- const newContent = removeTemplate(content, 'Greeting');
- const templates = Templates.parseText(newContent).toArray();
+ const lgFile = parse('a.lg', content, []);
+ const updatedLgFile = removeTemplate(lgFile, 'Greeting');
+ const templates = Templates.parseText(updatedLgFile.content).toArray();
expect(templates.length).toEqual(1);
expect(templates[0].name).toEqual('Exit');
});
diff --git a/Composer/packages/lib/indexers/__tests__/luUtil.test.ts b/Composer/packages/lib/indexers/__tests__/luUtil.test.ts
index 5f79d900ea..4068b2267c 100644
--- a/Composer/packages/lib/indexers/__tests__/luUtil.test.ts
+++ b/Composer/packages/lib/indexers/__tests__/luUtil.test.ts
@@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-
import { sectionHandler } from '@microsoft/bf-lu/lib/parser/composerindex';
import { updateIntent, addIntent, removeIntent } from '../src/utils/luUtil';
+import { luIndexer } from '../src/luIndexer';
const { luParser, luSectionTypes } = sectionHandler;
@@ -29,9 +29,11 @@ hi
# Foo
> nothing in body
`;
+ const fileId1 = 'a.lu';
+ const fileId2 = 'b.lu';
it('parse section test', () => {
- const luresource = luParser.parse(fileContent);
+ const luresource = luIndexer.parse(fileContent, fileId1).resource;
const { Sections, Errors, Content } = luresource;
expect(Content).toEqual(fileContent);
@@ -46,7 +48,7 @@ hi
});
it('parse section with syntax error test', () => {
- const luresource = luParser.parse(fileContentError1);
+ const luresource = luIndexer.parse(fileContentError1, fileId2).resource;
const { Sections, Errors, Content } = luresource;
expect(Content).toEqual(fileContentError1);
@@ -62,9 +64,10 @@ hi
Body: `- check my unread email
- show my unread emails`,
};
+ const luFile1 = luIndexer.parse(fileContent, fileId1);
- const fileContentUpdated = addIntent(fileContent, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1Updated = addIntent(luFile1, intent);
+ const luresource = luParser.parse(luFile1Updated.content);
const { Sections, Errors } = luresource;
expect(Errors.length).toEqual(0);
@@ -87,8 +90,15 @@ hi
- check my mail box please`,
};
- const fileContentUpdated = updateIntent(fileContent, intentName, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const intent2 = {
+ Name: 'CheckEmail',
+ Body: `- check my email
+- show my emails 2
+- check my mail box please`,
+ };
+ const luFile1 = luIndexer.parse(fileContent, fileId1);
+ const updatedLuFile = updateIntent(luFile1, intentName, intent);
+ const luresource = updatedLuFile.resource;
const { Sections, Errors } = luresource;
@@ -101,6 +111,21 @@ hi
expect(luresource.Sections[1].UtteranceAndEntitiesMap[0].utterance).toEqual('check my email');
expect(luresource.Sections[1].UtteranceAndEntitiesMap[1].utterance).toEqual('show my emails');
expect(luresource.Sections[1].UtteranceAndEntitiesMap[2].utterance).toEqual('check my mail box please');
+
+ // continue update on luresource
+ const updatedLuFile2 = updateIntent(updatedLuFile, intentName, intent2);
+ const luresource2 = updatedLuFile2.resource;
+
+ expect(luresource2.Errors.length).toEqual(0);
+ expect(luresource2.Sections.length).toEqual(2);
+ expect(luresource2.Sections[1].Errors.length).toEqual(0);
+ expect(luresource2.Sections[1].SectionType).toEqual(luSectionTypes.SIMPLEINTENTSECTION);
+ expect(luresource2.Sections[1].Name).toEqual('CheckEmail');
+ expect(luresource2.Sections[1].UtteranceAndEntitiesMap.length).toEqual(3);
+ expect(luresource2.Sections[1].UtteranceAndEntitiesMap[0].utterance).toEqual('check my email');
+ expect(luresource2.Sections[1].UtteranceAndEntitiesMap[1].utterance).toEqual('show my emails 2');
+ expect(luresource.Sections[1].UtteranceAndEntitiesMap[1].utterance).toEqual('show my emails'); // do not modify arguments
+ expect(luresource2.Sections[1].UtteranceAndEntitiesMap[2].utterance).toEqual('check my mail box please');
});
it('update section with syntax error: missing -', () => {
@@ -124,13 +149,17 @@ hi
`,
};
+ const luFile1 = luIndexer.parse(validFileContent);
+
// when intent invalid, after update can still be parsed
- const updatedContent2 = updateIntent(validFileContent, intentName, invalidIntent);
+ const updatedContent2 = updateIntent(luFile1, intentName, invalidIntent).content;
const updatedContent2Parsed = luParser.parse(updatedContent2);
expect(updatedContent2Parsed.Sections.length).toEqual(1);
expect(updatedContent2Parsed.Errors.length).toBeGreaterThan(0);
// when file invalid, update with valid intent should fix error.
- const updatedContent3 = updateIntent(updatedContent2, intentName, validIntent);
+ const luFile2 = luIndexer.parse(updatedContent2);
+
+ const updatedContent3 = updateIntent(luFile2, intentName, validIntent).content;
const updatedContent3Parsed = luParser.parse(updatedContent3);
expect(updatedContent3Parsed.Sections.length).toEqual(1);
expect(updatedContent3Parsed.Errors.length).toEqual(0);
@@ -149,9 +178,10 @@ hi
- show my emails
@`,
};
+ const luFile1 = luIndexer.parse(validFileContent);
// when intent invalid, after update can still be parsed
- const updatedContent2 = updateIntent(validFileContent, intentName, invalidIntent);
+ const updatedContent2 = updateIntent(luFile1, intentName, invalidIntent).content;
const updatedContent2Parsed = luParser.parse(updatedContent2);
expect(updatedContent2Parsed.Errors.length).toBeGreaterThan(0);
// TODO: update back should fix error.
@@ -174,8 +204,10 @@ hi
# UnexpectedIntentDefination
`,
};
+ const luFile1 = luIndexer.parse(validFileContent);
+
// should auto escape # to \#
- const updatedContent2 = updateIntent(validFileContent, intentName, invalidIntent);
+ const updatedContent2 = updateIntent(luFile1, intentName, invalidIntent).content;
const { Sections, Errors } = luParser.parse(updatedContent2);
expect(Errors.length).toEqual(0);
expect(Sections.length).toEqual(1);
@@ -187,7 +219,8 @@ hi
it('delete section test', () => {
const intentName = 'CheckEmail';
- const fileContentUpdated = removeIntent(fileContent, intentName);
+ const luFile1 = luIndexer.parse(fileContent, fileId1);
+ const fileContentUpdated = removeIntent(luFile1, intentName).content;
const luresource = luParser.parse(fileContentUpdated);
const { Sections, Errors } = luresource;
@@ -215,6 +248,7 @@ describe('LU Nested Section CRUD test', () => {
- show my deleted todos
@ simple todoSubject`;
+ const fileId = 'a.lu';
it('update IntentSection test', () => {
const intentName = 'CheckTodo';
@@ -228,9 +262,10 @@ describe('LU Nested Section CRUD test', () => {
`,
};
- const fileContentUpdated = updateIntent(fileContent, intentName, intent);
- const luresource = luParser.parse(fileContentUpdated);
- const { Sections, Errors } = luresource;
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated = updateIntent(luFile1, intentName, intent);
+ const result = luParser.parse(luFile1Updated.content);
+ const { Sections, Errors } = result;
expect(Errors.length).toEqual(0);
expect(Sections.length).toEqual(2);
@@ -270,8 +305,10 @@ describe('LU Nested Section CRUD test', () => {
`,
};
- const fileContentUpdated = addIntent(fileContent, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated = addIntent(luFile1, intent);
+ const luresource = luParser.parse(luFile1Updated.content);
+
const { Sections, Errors } = luresource;
expect(Errors.length).toEqual(0);
@@ -300,8 +337,10 @@ describe('LU Nested Section CRUD test', () => {
`,
};
- const fileContentUpdated = addIntent(fileContent, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated = addIntent(luFile1, intent);
+ const luresource = luParser.parse(luFile1Updated.content);
+
const { Sections, Errors } = luresource;
expect(Errors.length).toEqual(0);
@@ -333,8 +372,10 @@ describe('LU Nested Section CRUD test', () => {
`,
};
- const fileContentUpdated = updateIntent(fileContent, intentName, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated = updateIntent(luFile1, intentName, intent);
+ const luresource = luParser.parse(luFile1Updated.content);
+
const { Sections, Errors } = luresource;
expect(Errors.length).toEqual(0);
@@ -370,8 +411,10 @@ describe('LU Nested Section CRUD test', () => {
`,
};
- const fileContentUpdated = updateIntent(fileContent, intentName, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated = updateIntent(luFile1, intentName, intent);
+ const luresource = luParser.parse(luFile1Updated.content);
+
const { Sections, Errors } = luresource;
expect(Errors.length).toEqual(0);
@@ -400,16 +443,18 @@ describe('LU Nested Section CRUD test', () => {
### Oops
`;
- const fileContentUpdated1 = updateIntent(fileContent, intentName, { Name: intentName, Body: intentBody1 });
- const luresource1 = luParser.parse(fileContentUpdated1);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated1 = updateIntent(luFile1, intentName, { Name: intentName, Body: intentBody1 });
+ const luresource1 = luParser.parse(luFile1Updated1.content);
+
expect(luresource1.Sections.length).toBeGreaterThan(0);
expect(luresource1.Errors.length).toBeGreaterThan(0);
const intentBody2 = `## Oops
### Oops
`;
- const fileContentUpdated2 = updateIntent(fileContent, intentName, { Name: intentName, Body: intentBody2 });
- const luresource2 = luParser.parse(fileContentUpdated2);
+ const luFile1Updated2 = updateIntent(luFile1, intentName, { Name: intentName, Body: intentBody2 });
+ const luresource2 = luParser.parse(luFile1Updated2.content);
expect(luresource2.Sections.length).toEqual(2);
expect(luresource2.Errors.length).toBeGreaterThan(0);
expect(luresource2.Sections[0].SectionType).toEqual(luSectionTypes.MODELINFOSECTION);
@@ -425,8 +470,9 @@ describe('LU Nested Section CRUD test', () => {
const intentBody3 = `## Oops
### Oops
`;
- const fileContentUpdated3 = updateIntent(fileContent3, intentName, { Name: intentName, Body: intentBody3 });
- const luresource3 = luParser.parse(fileContentUpdated3);
+ const luFile2 = luIndexer.parse(fileContent3, fileId);
+ const luFile1Updated3 = updateIntent(luFile2, intentName, { Name: intentName, Body: intentBody3 });
+ const luresource3 = luParser.parse(luFile1Updated3.content);
expect(luresource3.Sections.length).toBeGreaterThan(0);
expect(luresource3.Errors.length).toBeGreaterThan(0);
});
@@ -446,8 +492,10 @@ describe('LU Nested Section CRUD test', () => {
`,
};
- const fileContentUpdated = updateIntent(fileContent, intentName, intent);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+
+ const luFile1Updated = updateIntent(luFile1, intentName, intent);
+ const luresource = luParser.parse(luFile1Updated.content);
const { Sections, Errors } = luresource;
expect(Errors.length).toEqual(0);
@@ -473,8 +521,9 @@ describe('LU Nested Section CRUD test', () => {
it('delete nestedIntentSection test', () => {
const Name = 'CheckTodo/CheckUnreadTodo';
- const fileContentUpdated = removeIntent(fileContent, Name);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+ const luFile1Updated = removeIntent(luFile1, Name);
+ const luresource = luParser.parse(luFile1Updated.content);
const { Sections, Errors } = luresource;
@@ -495,16 +544,20 @@ describe('LU Nested Section CRUD test', () => {
it('delete nestedIntentSection test, parrent not exist', () => {
const Name = 'CheckTodoNotExist/CheckUnreadTodo';
- const fileContentUpdated = removeIntent(fileContent, Name);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+
+ const luFile1Updated = removeIntent(luFile1, Name);
+ const luresource = luParser.parse(luFile1Updated.content);
const { Content } = luresource;
expect(Content).toEqual(fileContent);
});
it('delete nestedIntentSection test, child not exist', () => {
const Name = 'CheckTodo/CheckUnreadTodoNotExist';
- const fileContentUpdated = removeIntent(fileContent, Name);
- const luresource = luParser.parse(fileContentUpdated);
+ const luFile1 = luIndexer.parse(fileContent, fileId);
+
+ const luFile1Updated = removeIntent(luFile1, Name);
+ const luresource = luParser.parse(luFile1Updated.content);
const { Content } = luresource;
expect(Content).toEqual(fileContent);
});
diff --git a/Composer/packages/lib/indexers/package.json b/Composer/packages/lib/indexers/package.json
index 7ca30a113c..e7a4e6e50c 100644
--- a/Composer/packages/lib/indexers/package.json
+++ b/Composer/packages/lib/indexers/package.json
@@ -28,9 +28,9 @@
},
"dependencies": {
"@bfc/shared": "*",
- "@microsoft/bf-lu": "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-1.3.6.tgz",
+ "@microsoft/bf-lu": "^4.10.0-dev.20200728.930f45e",
"adaptive-expressions": "4.10.0-preview-147186",
- "botbuilder-lg": "4.10.0-preview-147186",
+ "botbuilder-lg": "^4.10.0-preview-150886",
"lodash": "^4.17.19"
}
}
\ No newline at end of file
diff --git a/Composer/packages/lib/indexers/src/luIndexer.ts b/Composer/packages/lib/indexers/src/luIndexer.ts
index 553a6e57e3..f77176c762 100644
--- a/Composer/packages/lib/indexers/src/luIndexer.ts
+++ b/Composer/packages/lib/indexers/src/luIndexer.ts
@@ -2,94 +2,17 @@
// Licensed under the MIT License.
import { sectionHandler } from '@microsoft/bf-lu/lib/parser/composerindex';
-import get from 'lodash/get';
-import {
- FileInfo,
- LuFile,
- LuParsed,
- LuSectionTypes,
- LuIntentSection,
- Diagnostic,
- Position,
- Range,
- DiagnosticSeverity,
-} from '@bfc/shared';
+import { FileInfo, LuFile } from '@bfc/shared';
import { getBaseName } from './utils/help';
import { FileExtensions } from './utils/fileExtensions';
+import { convertLuParseResultToLuFile } from './utils/luUtil';
const { luParser } = sectionHandler;
-function convertLuDiagnostic(d: any, source: string): Diagnostic {
- const severityMap = {
- ERROR: DiagnosticSeverity.Error,
- WARN: DiagnosticSeverity.Warning,
- INFORMATION: DiagnosticSeverity.Information,
- HINT: DiagnosticSeverity.Hint,
- };
- const result = new Diagnostic(d.Message, source, severityMap[d.Severity]);
-
- const start: Position = d.Range ? new Position(d.Range.Start.Line, d.Range.Start.Character) : new Position(0, 0);
- const end: Position = d.Range ? new Position(d.Range.End.Line, d.Range.End.Character) : new Position(0, 0);
- result.range = new Range(start, end);
-
- return result;
-}
-
-function parse(content: string, id = ''): LuParsed {
- const { Sections, Errors } = luParser.parse(content);
- const intents: LuIntentSection[] = [];
- Sections.forEach((section) => {
- const { Name, Body, SectionType } = section;
- const range = {
- startLineNumber: get(section, 'ParseTree.start.line', 0),
- endLineNumber: get(section, 'ParseTree.stop.line', 0),
- };
- if (SectionType === LuSectionTypes.SIMPLEINTENTSECTION) {
- const Entities = section.Entities.map(({ Name }) => Name);
- intents.push({
- Name,
- Body,
- Entities,
- range,
- });
- } else if (SectionType === LuSectionTypes.NESTEDINTENTSECTION) {
- const Children = section.SimpleIntentSections.map((subSection) => {
- const { Name, Body } = subSection;
- const range = {
- startLineNumber: get(subSection, 'ParseTree.start.line', 0),
- endLineNumber: get(subSection, 'ParseTree.stop.line', 0),
- };
- const Entities = subSection.Entities.map(({ Name }) => Name);
- return {
- Name,
- Body,
- Entities,
- range,
- };
- });
- intents.push({
- Name,
- Body,
- Children,
- range,
- });
- intents.push(
- ...Children.map((subSection) => {
- return {
- ...subSection,
- Name: `${section.Name}/${subSection.Name}`,
- };
- })
- );
- }
- });
- const diagnostics = Errors.map((e) => convertLuDiagnostic(e, id));
- return {
- empty: !Sections.length,
- intents,
- diagnostics,
- };
+function parse(content: string, id = ''): LuFile {
+ const result = luParser.parse(content);
+ return convertLuParseResultToLuFile(id, result);
}
function index(files: FileInfo[]): LuFile[] {
@@ -100,7 +23,7 @@ function index(files: FileInfo[]): LuFile[] {
const luFiles = filtered.map((file) => {
const { name, content } = file;
const id = getBaseName(name);
- return { id, content, ...parse(content, id) };
+ return parse(content, id);
});
return luFiles;
diff --git a/Composer/packages/lib/indexers/src/utils/lgUtil.ts b/Composer/packages/lib/indexers/src/utils/lgUtil.ts
index 6d173a9caa..c6f7dfea4b 100644
--- a/Composer/packages/lib/indexers/src/utils/lgUtil.ts
+++ b/Composer/packages/lib/indexers/src/utils/lgUtil.ts
@@ -38,8 +38,8 @@ export function convertTemplatesToLgFile(id = '', content: string, templates: Te
body: t.body,
parameters: t.parameters,
range: {
- startLineNumber: get(t, 'sourceRange.parseTree.start.line', 0),
- endLineNumber: get(t, 'sourceRange.parseTree.stop.line', 0),
+ startLineNumber: get(t, 'sourceRange.range.start.line', 0),
+ endLineNumber: get(t, 'sourceRange.range.end.line', 0),
},
};
});
@@ -64,12 +64,12 @@ export function increaseNameUtilNotExist(templates: LgTemplate[], name: string):
}
export function updateTemplate(
- id = '',
- content: string,
+ lgFile: LgFile,
templateName: string,
{ name, parameters, body }: { name?: string; parameters?: string[]; body?: string },
importResolver?: ImportResolverDelegate
): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
const originTemplate = resource.toArray().find((t) => t.name === templateName);
let templates;
@@ -90,22 +90,18 @@ export function updateTemplate(
// if name exist, throw error.
export function addTemplate(
- id = '',
- content: string,
+ lgFile: LgFile,
{ name, parameters = [], body }: LgTemplate,
importResolver?: ImportResolverDelegate
): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
const templates = resource.addTemplate(name, parameters, body);
return convertTemplatesToLgFile(id, templates.toString(), templates);
}
-export function addTemplates(
- id = '',
- content: string,
- templates: LgTemplate[],
- importResolver?: ImportResolverDelegate
-): LgFile {
+export function addTemplates(lgFile: LgFile, templates: LgTemplate[], importResolver?: ImportResolverDelegate): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
for (const { name, parameters = [], body } of templates) {
resource.addTemplate(name, parameters, body);
@@ -115,11 +111,11 @@ export function addTemplates(
// if name exist, add it anyway, with name like `${name}1` `${name}2`
export function addTemplateAnyway(
- id = '',
- content: string,
+ lgFile: LgFile,
{ name = 'TemplateName', parameters = [], body = '-TemplateBody' }: LgTemplate,
importResolver?: ImportResolverDelegate
): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
const newName = increaseNameUtilNotExist(resource.toArray(), name);
@@ -129,12 +125,12 @@ export function addTemplateAnyway(
// if toTemplateName exist, throw error.
export function copyTemplate(
- id = '',
- content: string,
+ lgFile: LgFile,
fromTemplateName: string,
toTemplateName: string,
importResolver?: ImportResolverDelegate
): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
const fromTemplate = resource.toArray().find((t) => t.name === fromTemplateName);
if (!fromTemplate) {
@@ -147,12 +143,12 @@ export function copyTemplate(
// if toTemplateName exist, add it anyway, with name like `${toTemplateName}1` `${toTemplateName}2`
export function copyTemplateAnyway(
- id = '',
- content: string,
+ lgFile: LgFile,
fromTemplateName: string,
toTemplateName?: string,
importResolver?: ImportResolverDelegate
): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
const fromTemplate = resource.toArray().find((t) => t.name === fromTemplateName);
if (!fromTemplate) {
@@ -169,23 +165,19 @@ export function copyTemplateAnyway(
return convertTemplatesToLgFile(id, templates.toString(), templates);
}
-export function removeTemplate(
- id = '',
- content: string,
- templateName: string,
- importResolver?: ImportResolverDelegate
-): LgFile {
+export function removeTemplate(lgFile: LgFile, templateName: string, importResolver?: ImportResolverDelegate): LgFile {
+ const { id, content } = lgFile;
const resource = Templates.parseText(content, undefined, importResolver);
const templates = resource.deleteTemplate(templateName);
return convertTemplatesToLgFile(id, templates.toString(), templates);
}
export function removeTemplates(
- id = '',
- content: string,
+ lgFile: LgFile,
templateNames: string[],
importResolver?: ImportResolverDelegate
): LgFile {
+ const { id, content } = lgFile;
let resource = Templates.parseText(content, undefined, importResolver);
templateNames.forEach((templateName) => {
resource = resource.deleteTemplate(templateName);
diff --git a/Composer/packages/lib/indexers/src/utils/luUtil.ts b/Composer/packages/lib/indexers/src/utils/luUtil.ts
index 61c0736736..2bef9426ca 100644
--- a/Composer/packages/lib/indexers/src/utils/luUtil.ts
+++ b/Composer/packages/lib/indexers/src/utils/luUtil.ts
@@ -3,17 +3,16 @@
/**
* luUtil.ts is a single place use lu-parser handle lu file operation.
+ * Those methods should be implemented as pure function, shall not modify arguments.
* it's designed have no state, input text file, output text file.
* for more usage detail, please check client/__tests__/utils/luUtil.test.ts
*/
-
import { sectionHandler } from '@microsoft/bf-lu/lib/parser/composerindex';
import isEmpty from 'lodash/isEmpty';
-import { LuIntentSection, LuSectionTypes, Diagnostic } from '@bfc/shared';
+import get from 'lodash/get';
+import { LuFile, LuSectionTypes, LuIntentSection, Diagnostic, Position, Range, DiagnosticSeverity } from '@bfc/shared';
import formatMessage from 'format-message';
-import { luIndexer } from '../luIndexer';
-
import { buildNewlineText, splitNewlineText } from './help';
const { luParser, sectionOperator } = sectionHandler;
@@ -23,6 +22,67 @@ const NEWLINE = '\r\n';
// when new add a section in inline editor, the section haven't exist on file context, to make suggestion/validation possiable here mock one.
export const PlaceHolderSectionName = formatMessage(`_NewSectionPlaceHolderSectionName`);
+export function convertLuDiagnostic(d: any, source: string): Diagnostic {
+ const severityMap = {
+ ERROR: DiagnosticSeverity.Error,
+ WARN: DiagnosticSeverity.Warning,
+ INFORMATION: DiagnosticSeverity.Information,
+ HINT: DiagnosticSeverity.Hint,
+ };
+ const result = new Diagnostic(d.Message, source, severityMap[d.Severity]);
+
+ const start: Position = d.Range ? new Position(d.Range.Start.Line, d.Range.Start.Character) : new Position(0, 0);
+ const end: Position = d.Range ? new Position(d.Range.End.Line, d.Range.End.Character) : new Position(0, 0);
+ result.range = new Range(start, end);
+
+ return result;
+}
+
+export function convertLuParseResultToLuFile(id = '', resource): LuFile {
+ // filter structured-object from LUParser result.
+ const { Sections, Errors, Content } = resource;
+ const intents: LuIntentSection[] = [];
+ Sections.forEach((section) => {
+ const { Name, Body, SectionType } = section;
+ const range = {
+ startLineNumber: get(section, 'Range.Start.Line', 0),
+ endLineNumber: get(section, 'Range.End.Line', 0),
+ };
+ if (SectionType === LuSectionTypes.SIMPLEINTENTSECTION) {
+ const Entities = section.Entities.map(({ Name }) => Name);
+ intents.push({ Name, Body, Entities, range });
+ } else if (SectionType === LuSectionTypes.NESTEDINTENTSECTION) {
+ const Children = section.SimpleIntentSections.map((subSection) => {
+ const { Name, Body } = subSection;
+ const range = {
+ startLineNumber: get(subSection, 'Range.Start.Line', 0),
+ endLineNumber: get(subSection, 'Range.End.Line', 0),
+ };
+ const Entities = subSection.Entities.map(({ Name }) => Name);
+ return { Name, Body, Entities, range };
+ });
+ intents.push({ Name, Body, Children, range });
+ intents.push(
+ ...Children.map((subSection) => {
+ return {
+ ...subSection,
+ Name: `${section.Name}/${subSection.Name}`,
+ };
+ })
+ );
+ }
+ });
+ const diagnostics = Errors.map((e) => convertLuDiagnostic(e, id));
+ return {
+ id,
+ content: Content,
+ empty: !Sections.length,
+ intents,
+ diagnostics,
+ resource: { Sections, Errors, Content },
+ };
+}
+
export function isValid(diagnostics: any[]) {
return diagnostics.every((item) => {
item.Severity !== 'ERROR';
@@ -70,7 +130,9 @@ export function textFromIntents(intents: LuIntentSection[], nestedLevel = 1): st
export function checkSection(intent: LuIntentSection, enableSections = true): Diagnostic[] {
const text = textFromIntent(intent, 1, enableSections);
- return luIndexer.parse(text).diagnostics;
+ const result = luParser.parse(text);
+ const { Errors } = result;
+ return Errors.map((e) => convertLuDiagnostic(e, ''));
}
export function checkIsSingleSection(intent: LuIntentSection, enableSections = true): boolean {
@@ -108,11 +170,12 @@ function updateInSections(
* @param intentName intent Name, support subSection naming 'CheckEmail/CheckUnreadEmail'. if #CheckEmail not exist will do recursive add.
* @param {Name, Body} intent the updates. if intent is empty will do remove.
*/
-export function updateIntent(content: string, intentName: string, intent: LuIntentSection | null): string {
+export function updateIntent(luFile: LuFile, intentName: string, intent: LuIntentSection | null): LuFile {
let targetSection;
let targetSectionContent;
+ const { id, resource } = luFile;
+
const updatedSectionContent = textFromIntent(intent);
- const resource = luParser.parse(content);
const { Sections } = resource;
// if intent is null, do remove
// and if remove target not exist return origin content;
@@ -123,14 +186,15 @@ export function updateIntent(content: string, intentName: string, intent: LuInte
({ Name }) => Name === childName
);
if (!targetChildSection) {
- return content;
+ return luFile;
}
} else {
const targetSection = Sections.find(({ Name }) => Name === intentName);
if (targetSection) {
- return new sectionOperator(resource).deleteSection(targetSection.Id).Content;
+ const result = new sectionOperator(resource).deleteSection(targetSection.Id);
+ return convertLuParseResultToLuFile(id, result);
}
- return content;
+ return luFile;
}
}
@@ -150,13 +214,15 @@ export function updateIntent(content: string, intentName: string, intent: LuInte
targetSectionContent = updatedSectionContent;
}
+ let newResource;
// update
if (targetSection) {
- return new sectionOperator(resource).updateSection(targetSection.Id, targetSectionContent).Content;
+ newResource = new sectionOperator(resource).updateSection(targetSection.Id, targetSectionContent);
// add if not exist
} else {
- return new sectionOperator(resource).addSection(['', targetSectionContent].join(NEWLINE)).Content;
+ newResource = new sectionOperator(resource).addSection(['', targetSectionContent].join(NEWLINE));
}
+ return convertLuParseResultToLuFile(id, newResource);
}
/**
@@ -164,18 +230,18 @@ export function updateIntent(content: string, intentName: string, intent: LuInte
* @param content origin lu file content
* @param {Name, Body} intent the adds. Name support subSection naming 'CheckEmail/CheckUnreadEmail', if #CheckEmail not exist will do recursive add.
*/
-export function addIntent(content: string, { Name, Body, Entities }: LuIntentSection): string {
+export function addIntent(luFile: LuFile, { Name, Body, Entities }: LuIntentSection): LuFile {
const intentName = Name;
if (Name.includes('/')) {
const [, childName] = Name.split('/');
Name = childName;
}
// If the invoker doesn't want to carry Entities, don't pass Entities in.
- return updateIntent(content, intentName, { Name, Body, Entities });
+ return updateIntent(luFile, intentName, { Name, Body, Entities });
}
-export function addIntents(content: string, intents: LuIntentSection[]): string {
- let result = content;
+export function addIntents(luFile: LuFile, intents: LuIntentSection[]): LuFile {
+ let result = luFile;
for (const intent of intents) {
result = addIntent(result, intent);
}
@@ -187,26 +253,18 @@ export function addIntents(content: string, intents: LuIntentSection[]): string
* @param content origin lu file content
* @param intentName the remove intentName. Name support subSection naming 'CheckEmail/CheckUnreadEmail', if any of them not exist will do nothing.
*/
-export function removeIntent(content: string, intentName: string): string {
- if (intentName.includes('/')) {
- return updateIntent(content, intentName, null);
- }
- const resource = luParser.parse(content);
- const { Sections } = resource;
- const targetSection = Sections.find(({ Name }) => Name === intentName);
- if (targetSection) {
- return new sectionOperator(resource).deleteSection(targetSection.Id).Content;
- }
- return content;
+export function removeIntent(luFile: LuFile, intentName: string): LuFile {
+ return updateIntent(luFile, intentName, null);
}
-export function removeIntents(content: string, intentNames: string[]): string {
- let result = content;
+export function removeIntents(luFile: LuFile, intentNames: string[]): LuFile {
+ let result = luFile;
for (const intentName of intentNames) {
result = removeIntent(result, intentName);
}
return result;
}
-export function parse(id: string, content: string) {
- return { id, content, ...luIndexer.parse(content, id) };
+export function parse(id: string, content: string): LuFile {
+ const result = luParser.parse(content);
+ return convertLuParseResultToLuFile(id, result);
}
diff --git a/Composer/packages/lib/shared/src/dialogFactory.ts b/Composer/packages/lib/shared/src/dialogFactory.ts
index 4fcffa19bb..051f1ac99f 100644
--- a/Composer/packages/lib/shared/src/dialogFactory.ts
+++ b/Composer/packages/lib/shared/src/dialogFactory.ts
@@ -87,45 +87,154 @@ const initialDialogShape = () => ({
},
[SDKKinds.OnChooseIntent]: {
$kind: SDKKinds.OnChooseIntent,
+ $designer: {
+ id: generateDesignerId(),
+ },
actions: [
{
$kind: SDKKinds.SetProperty,
$designer: {
id: generateDesignerId(),
},
- property: 'dialog.recognized',
- value: '=turn.recognized',
+ assignments: [
+ {
+ value: '=turn.recognized.candidates[0]',
+ property: 'dialog.luisResult',
+ },
+ {
+ property: 'dialog.qnaResult',
+ value: '=turn.recognized.candidates[1]',
+ },
+ ],
+ },
+ {
+ $kind: SDKKinds.IfCondition,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ condition: 'dialog.luisResult.score >= 0.9 && dialog.qnaResult.score <= 0.5',
+ actions: [
+ {
+ $kind: SDKKinds.EmitEvent,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ eventName: 'recognizedIntent',
+ eventValue: '=dialog.luisResult.result',
+ disabled: true,
+ },
+ {
+ $kind: SDKKinds.BreakLoop,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ disabled: true,
+ },
+ ],
+ disabled: true,
+ },
+ {
+ $kind: SDKKinds.IfCondition,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ condition: 'dialog.luisResult.score <= 0.5 && dialog.qnaResult.score >= 0.9',
+ actions: [
+ {
+ $kind: SDKKinds.EmitEvent,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ eventName: 'recognizedIntent',
+ eventValue: '=dialog.qnaResult.result',
+ disabled: true,
+ },
+ {
+ $kind: SDKKinds.BreakLoop,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ disabled: true,
+ },
+ ],
+ disabled: true,
},
{
- $kind: SDKKinds.ChoiceInput,
+ $kind: SDKKinds.IfCondition,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ condition: 'dialog.qnaResult.score <= 0.05',
+ actions: [
+ {
+ $kind: SDKKinds.EmitEvent,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ eventName: 'recognizedIntent',
+ eventValue: '=dialog.luisResult.result',
+ disabled: true,
+ },
+ {
+ $kind: SDKKinds.BreakLoop,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ disabled: true,
+ },
+ ],
+ top: 3,
+ disabled: true,
+ cardNoMatchResponse: 'Thanks for the feedback.',
+ cardNoMatchText: 'None of the above.',
+ },
+ {
+ $kind: SDKKinds.TextInput,
$designer: {
id: generateDesignerId(),
},
- defaultLocale: 'en-us',
disabled: false,
maxTurnCount: 3,
- alwaysPrompt: false,
+ alwaysPrompt: true,
allowInterruptions: false,
prompt: '',
- choiceOptions: {
- includeNumbers: true,
- inlineOrMore: ', or ',
- inlineOr: ' or ',
- inlineSeparator: ', ',
- },
- property: 'dialog.choice',
- choices: '=foreach(dialog.recognized.candidates, x, x.intent)',
- outputFormat: 'index',
+ property: 'turn.intentChoice',
+ value: '=@userChosenIntent',
top: 3,
cardNoMatchResponse: 'Thanks for the feedback.',
+ cardNoMatchText: 'None of the above.',
+ activeLearningCardTitle: 'Did you mean:',
+ threshold: 0.3,
+ noAnswer: 'Sorry, I did not find an answer.',
+ hostname: '=settings.qna.hostname',
+ endpointKey: '=settings.qna.endpointkey',
+ knowledgeBaseId: '=settings.qna.knowledgebaseid',
},
{
- $kind: SDKKinds.EmitEvent,
+ $kind: SDKKinds.IfCondition,
$designer: {
id: generateDesignerId(),
},
- eventValue: '=dialog.recognized.candidates[dialog.choice].result',
- eventName: 'recognizedIntent',
+ condition: "turn.intentChoice != 'none'",
+ actions: [
+ {
+ $kind: SDKKinds.EmitEvent,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ eventName: 'recognizedIntent',
+ eventValue: '=dialog[turn.intentChoice].result',
+ },
+ ],
+ elseActions: [
+ {
+ $kind: SDKKinds.SendActivity,
+ $designer: {
+ id: generateDesignerId(),
+ },
+ activity: '',
+ },
+ ],
top: 3,
cardNoMatchResponse: 'Thanks for the feedback.',
cardNoMatchText: 'None of the above.',
diff --git a/Composer/packages/lib/shared/src/types/EditorAPI.ts b/Composer/packages/lib/shared/src/types/EditorAPI.ts
new file mode 100644
index 0000000000..0a458faf08
--- /dev/null
+++ b/Composer/packages/lib/shared/src/types/EditorAPI.ts
@@ -0,0 +1,66 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+type EditorAPIHandler = () => any;
+
+export interface EditorAPI {
+ Editing: {
+ Undo: EditorAPIHandler;
+ Redo: EditorAPIHandler;
+ };
+ Actions: {
+ CopySelection: EditorAPIHandler;
+ CutSelection: EditorAPIHandler;
+ MoveSelection: EditorAPIHandler;
+ DeleteSelection: EditorAPIHandler;
+ DisableSelection: EditorAPIHandler;
+ EnableSelection: EditorAPIHandler;
+ };
+}
+
+const EmptyHandler = () => null;
+
+const DefaultEditorAPI: EditorAPI = {
+ Editing: {
+ Undo: EmptyHandler,
+ Redo: EmptyHandler,
+ },
+ Actions: {
+ CopySelection: EmptyHandler,
+ CutSelection: EmptyHandler,
+ MoveSelection: EmptyHandler,
+ DeleteSelection: EmptyHandler,
+ DisableSelection: EmptyHandler,
+ EnableSelection: EmptyHandler,
+ },
+};
+
+const EDITOR_API_NAME = 'EditorAPI';
+
+export function getEditorAPI(): EditorAPI {
+ if (!window[EDITOR_API_NAME]) {
+ window[EDITOR_API_NAME] = { ...DefaultEditorAPI };
+ }
+ return window[EDITOR_API_NAME];
+}
+
+export function registerEditorAPI(domain: 'Editing' | 'Actions', handlers: { [fn: string]: EditorAPIHandler }) {
+ const editorAPI: EditorAPI = getEditorAPI();
+
+ // reject unrecognized api domain.
+ if (!editorAPI[domain]) return;
+
+ const domainAPIs = editorAPI[domain];
+ const overridedAPIs = Object.keys(handlers)
+ .filter((fnName) => !!domainAPIs[fnName])
+ .reduce((results, fnName) => {
+ results[fnName] = handlers[fnName];
+ return results;
+ }, {});
+
+ const newDomainAPIs = {
+ ...domainAPIs,
+ ...overridedAPIs,
+ };
+ editorAPI[domain] = newDomainAPIs as any;
+}
diff --git a/Composer/packages/lib/shared/src/types/index.ts b/Composer/packages/lib/shared/src/types/index.ts
index 77dd246431..ab3827c46c 100644
--- a/Composer/packages/lib/shared/src/types/index.ts
+++ b/Composer/packages/lib/shared/src/types/index.ts
@@ -9,3 +9,4 @@ export * from './sdk';
export * from './settings';
export * from './server';
export * from './shell';
+export * from './EditorAPI';
diff --git a/Composer/packages/server/package.json b/Composer/packages/server/package.json
index 36db42c499..9d2bb000c5 100644
--- a/Composer/packages/server/package.json
+++ b/Composer/packages/server/package.json
@@ -61,7 +61,7 @@
"@bfc/plugin-loader": "*",
"@bfc/shared": "*",
"@microsoft/bf-dispatcher": "^4.10.0-preview.141651",
- "@microsoft/bf-lu": "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/bf-lu/-/@bfcomposer/bf-lu-1.4.2.tgz",
+ "@microsoft/bf-lu": "^4.10.0-dev.20200728.930f45e",
"archiver": "^3.0.0",
"axios": "^0.19.2",
"azure-storage": "^2.10.3",
diff --git a/Composer/packages/server/src/models/bot/builder.ts b/Composer/packages/server/src/models/bot/builder.ts
index 7035b2dcf3..990e61dfea 100644
--- a/Composer/packages/server/src/models/bot/builder.ts
+++ b/Composer/packages/server/src/models/bot/builder.ts
@@ -214,6 +214,7 @@ export class Builder {
config.botName,
config.suffix,
config.fallbackLocal,
+ true,
false,
false,
loadResult.multiRecognizers,
diff --git a/Composer/packages/tools/language-servers/language-generation/package.json b/Composer/packages/tools/language-servers/language-generation/package.json
index 78cee92ee4..5d102abca0 100644
--- a/Composer/packages/tools/language-servers/language-generation/package.json
+++ b/Composer/packages/tools/language-servers/language-generation/package.json
@@ -16,7 +16,7 @@
},
"dependencies": {
"@bfc/indexers": "*",
- "botbuilder-lg": "4.10.0-preview-147186",
+ "botbuilder-lg": "^4.10.0-preview-150886",
"vscode-languageserver": "^5.3.0-next"
},
"devDependencies": {
diff --git a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts
index 77a3b3d9e5..1e97a25c2e 100644
--- a/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts
+++ b/Composer/packages/tools/language-servers/language-generation/src/LGServer.ts
@@ -15,9 +15,8 @@ import {
} from 'vscode-languageserver-types';
import { TextDocumentPositionParams, DocumentOnTypeFormattingParams } from 'vscode-languageserver-protocol';
import get from 'lodash/get';
-import { filterTemplateDiagnostics, isValid } from '@bfc/indexers';
-import { MemoryResolver, ResolverResource, LgTemplate } from '@bfc/shared';
-import * as lgUtil from '@bfc/indexers/lib/utils/lgUtil';
+import { filterTemplateDiagnostics, isValid, lgUtil } from '@bfc/indexers';
+import { MemoryResolver, ResolverResource, LgFile } from '@bfc/shared';
import { LgParser } from './lgParser';
import { buildInfunctionsMap } from './builtinFunctionsMap';
@@ -159,30 +158,19 @@ export class LGServer {
protected addLGDocument(document: TextDocument, lgOption?: LGOption) {
const { uri } = document;
const { fileId, templateId, projectId } = lgOption || {};
- const index = async () => {
- let content = this.documents.get(uri)?.getText() || '';
+ const index = (): LgFile => {
+ const content = this.documents.get(uri)?.getText() || '';
// if inline mode, composite local with server resolved file.
- if (this.getLgResources && fileId && templateId) {
- const resources = this.getLgResources(projectId);
- const lastContent = resources.find((item) => item.id === fileId)?.content;
-
- if (lastContent) {
- const body = content;
- content = lgUtil.updateTemplate('', lastContent, templateId, { body }).content;
+ const lgTextFiles = projectId ? this.getLgResources(projectId) : [];
+ if (fileId && templateId) {
+ const lgTextFile = lgTextFiles.find((item) => item.id === fileId);
+ if (lgTextFile) {
+ const lgFile = lgUtil.parse(lgTextFile.id, lgTextFile.content, lgTextFiles);
+ return lgUtil.updateTemplate(lgFile, templateId, { body: content });
}
}
- const id = fileId || uri;
- let templates: LgTemplate[] = [];
- let diagnostics: any[] = [];
- try {
- const payload = await this._lgParser.parseText(content, id, this.getLgResources(projectId));
- templates = payload.templates;
- diagnostics = payload.diagnostics;
- } catch (error) {
- diagnostics.push(generageDiagnostic(error.message, DiagnosticSeverity.Error, document));
- }
- return { id, content, templates, diagnostics };
+ return lgUtil.parse(fileId || uri, content, lgTextFiles);
};
const lgDocument: LGDocument = {
uri,
@@ -203,7 +191,7 @@ export class LGServer {
if (!document) {
return Promise.resolve(null);
}
- const lgFile = await this.getLGDocument(document)?.index();
+ const lgFile = this.getLGDocument(document)?.index();
if (!lgFile) {
return Promise.resolve(null);
}
@@ -477,7 +465,7 @@ export class LGServer {
const wordAtCurRange = document.getText(range);
const endWithDot = wordAtCurRange.endsWith('.');
const lgDoc = this.getLGDocument(document);
- const lgFile = await lgDoc?.index();
+ const lgFile = lgDoc?.index();
const templateId = lgDoc?.templateId;
const lines = document.getText(range).split('\n');
if (!lgFile) {
@@ -700,7 +688,7 @@ export class LGServer {
return;
}
const { fileId, templateId, uri, projectId } = lgDoc;
- const lgFile = await lgDoc.index();
+ const lgFile = lgDoc.index();
if (!lgFile) {
return;
}
@@ -737,7 +725,11 @@ export class LGServer {
}
let lgDiagnostics: any[] = [];
try {
- const payload = await this._lgParser.parseText(text, fileId || uri, this.getLgResources(projectId));
+ const payload = await this._lgParser.parseText(
+ text,
+ fileId || uri,
+ projectId ? this.getLgResources(projectId) : []
+ );
lgDiagnostics = payload.diagnostics;
} catch (error) {
lgDiagnostics.push(generageDiagnostic(error.message, DiagnosticSeverity.Error, document));
diff --git a/Composer/packages/tools/language-servers/language-generation/src/utils.ts b/Composer/packages/tools/language-servers/language-generation/src/utils.ts
index 5faed76d55..ec48be8c21 100644
--- a/Composer/packages/tools/language-servers/language-generation/src/utils.ts
+++ b/Composer/packages/tools/language-servers/language-generation/src/utils.ts
@@ -36,7 +36,7 @@ export interface LGDocument {
projectId?: string;
fileId?: string;
templateId?: string;
- index: () => Promise;
+ index: () => LgFile;
}
export type LGFileResolver = (id: string) => LgFile | undefined;
diff --git a/Composer/packages/tools/language-servers/language-understanding/package.json b/Composer/packages/tools/language-servers/language-understanding/package.json
index 4ac60bcec8..93493aa6a4 100644
--- a/Composer/packages/tools/language-servers/language-understanding/package.json
+++ b/Composer/packages/tools/language-servers/language-understanding/package.json
@@ -19,7 +19,7 @@
},
"dependencies": {
"@microsoft/bf-cli-command": "^4.10.0-preview.141651",
- "@microsoft/bf-lu": "^4.10.0-preview.141651",
+ "@microsoft/bf-lu": "^4.10.0-dev.20200728.930f45e",
"express": "^4.15.2",
"monaco-languageclient": "^0.10.0",
"normalize-url": "^2.0.1",
diff --git a/Composer/packages/tools/language-servers/language-understanding/src/LUServer.ts b/Composer/packages/tools/language-servers/language-understanding/src/LUServer.ts
index 0b38e28bf6..10374312c4 100644
--- a/Composer/packages/tools/language-servers/language-understanding/src/LUServer.ts
+++ b/Composer/packages/tools/language-servers/language-understanding/src/LUServer.ts
@@ -135,12 +135,13 @@ export class LUServer {
if (this.importResolver && fileId && projectId) {
const resolver = this.importResolver;
return (source: string, id: string) => {
- const luFile = resolver(source, id, projectId);
- if (!luFile) {
+ const plainLuFile = resolver(source, id, projectId);
+ if (!plainLuFile) {
this.sendDiagnostics(document, [
generageDiagnostic(`lu file: ${fileId}.lu not exist on server`, DiagnosticSeverity.Error, document),
]);
}
+ const luFile = luIndexer.parse(plainLuFile.content, plainLuFile.id);
let { content } = luFile;
/**
* source is . means use as file resolver, not import resolver
@@ -148,7 +149,7 @@ export class LUServer {
* so here build the full content from server file content and editor content
*/
if (source === '.' && sectionId) {
- content = updateIntent(luFile.content, sectionId, { Name: sectionId, Body: editorContent });
+ content = updateIntent(luFile, sectionId, { Name: sectionId, Body: editorContent }).content;
}
return { id, content };
};
diff --git a/Composer/plugins/lib/bot-deploy/package.json b/Composer/plugins/lib/bot-deploy/package.json
index 9e5b9c110c..1e6e7759cb 100644
--- a/Composer/plugins/lib/bot-deploy/package.json
+++ b/Composer/plugins/lib/bot-deploy/package.json
@@ -20,8 +20,8 @@
"@azure/graph": "^5.0.1",
"@azure/ms-rest-browserauth": "^0.1.4",
"@azure/ms-rest-nodeauth": "^3.0.3",
- "@microsoft/bf-lu": "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/bf-lu/-/@bfcomposer/bf-lu-1.4.0.tgz",
- "@microsoft/bf-luis-cli": "^4.10.0-preview.141651",
+ "@microsoft/bf-lu": "^4.10.0-dev.20200728.930f45e",
+ "@microsoft/bf-luis-cli": "^4.10.0-dev.20200721.8bb21ac",
"@types/archiver": "^3.1.0",
"@types/fs-extra": "^8.1.0",
"@types/request": "^2.48.4",
diff --git a/Composer/plugins/lib/bot-deploy/src/botProjectDeploy.ts b/Composer/plugins/lib/bot-deploy/src/botProjectDeploy.ts
index 953f9698db..32b4edfbec 100644
--- a/Composer/plugins/lib/bot-deploy/src/botProjectDeploy.ts
+++ b/Composer/plugins/lib/bot-deploy/src/botProjectDeploy.ts
@@ -18,6 +18,7 @@ import { GraphRbacManagementClient } from '@azure/graph';
import { DeviceTokenCredentials } from '@azure/ms-rest-nodeauth';
import * as fs from 'fs-extra';
import * as rp from 'request-promise';
+import { FileInfo } from '@bfc/shared';
import { BotProjectDeployConfig } from './botProjectDeployConfig';
import { BotProjectDeployLoggerType } from './botProjectLoggerType';
@@ -424,13 +425,18 @@ export class BotProjectDeploy {
content: fs.readJSONSync(dialog),
});
}
- luFiles = luFiles.map((luFile) => luFile.substring(luFile.lastIndexOf('\\') + 1));
- this.crossTrainConfig = createCrossTrainConfig(dialogs, luFiles);
- }
- private needCrossTrain() {
- return this.crossTrainConfig.rootIds.length > 0;
+ const luFileInfos: FileInfo[] = luFiles.map((luFile) => {
+ const fileStats = fs.statSync(luFile);
+ return {
+ name: luFile.substring(luFile.lastIndexOf('\\') + 1),
+ content: fs.readFileSync(luFile, 'utf-8'),
+ lastModified: fileStats.mtime.toString(),
+ path: luFile,
+ relativePath: luFile.substring(luFile.lastIndexOf(this.remoteBotPath) + 1),
+ };
+ });
+ this.crossTrainConfig = createCrossTrainConfig(dialogs, luFileInfos);
}
-
private async writeCrossTrainFiles(crossTrainResult) {
if (!(await fs.pathExists(this.interruptionFolderPath))) {
await fs.mkdir(this.interruptionFolderPath);
@@ -443,7 +449,6 @@ export class BotProjectDeploy {
}
private async crossTrain(luFiles: string[], qnaFiles: string[]) {
- if (!this.needCrossTrain()) return;
const luContents: { [key: string]: any }[] = [];
const qnaContents: { [key: string]: any }[] = [];
for (const luFile of luFiles) {
@@ -465,7 +470,6 @@ export class BotProjectDeploy {
}
private async cleanCrossTrain() {
- if (!this.needCrossTrain()) return;
fs.rmdirSync(this.interruptionFolderPath, { recursive: true });
}
private async getInterruptionFiles() {
diff --git a/Composer/plugins/lib/bot-deploy/src/utils/crossTrainUtil.ts b/Composer/plugins/lib/bot-deploy/src/utils/crossTrainUtil.ts
index cc42eb60cd..471c457a79 100644
--- a/Composer/plugins/lib/bot-deploy/src/utils/crossTrainUtil.ts
+++ b/Composer/plugins/lib/bot-deploy/src/utils/crossTrainUtil.ts
@@ -7,7 +7,8 @@
* for more usage detail, please check client/__tests__/utils/luUtil.test.ts
*/
import keys from 'lodash/keys';
-import { LuFile, DialogInfo, IIntentTrigger, FieldNames, SDKKinds } from '@bfc/shared';
+import { LuFile, DialogInfo, IIntentTrigger, FieldNames, SDKKinds, FileInfo } from '@bfc/shared';
+import { luIndexer } from '@bfc/indexers';
import { getBaseName, getExtension } from './fileUtil';
import { VisitorFunc, JsonWalk } from './jsonWalk';
@@ -68,8 +69,8 @@ function createConfigId(fileId) {
return `${fileId}.lu`;
}
-function getLuFilesByDialogId(dialogId: string, luFiles: string[]) {
- return luFiles.filter((lu) => getBaseName(lu) === dialogId).map((lu) => createConfigId(lu));
+function getLuFilesByDialogId(dialogId: string, luFiles: LuFile[]) {
+ return luFiles.filter((lu) => getBaseName(lu.id) === dialogId).map((lu) => createConfigId(lu.id));
}
function getFileLocale(fileName: string) {
@@ -78,7 +79,7 @@ function getFileLocale(fileName: string) {
}
//replace the dialogId with luFile's name
-function addLocaleToConfig(config: ICrossTrainConfig, luFiles: string[]) {
+function addLocaleToConfig(config: ICrossTrainConfig, luFiles: LuFile[]) {
const { rootIds, triggerRules } = config;
config.rootIds = rootIds.reduce((result: string[], id: string) => {
return [...result, ...getLuFilesByDialogId(id, luFiles)];
@@ -152,7 +153,7 @@ export interface ICrossTrainConfig {
verbose: true
}
*/
-export function createCrossTrainConfig(dialogs: any[], luFiles: string[]): ICrossTrainConfig {
+export function createCrossTrainConfig(dialogs: any[], luFilesInfo: FileInfo[]): ICrossTrainConfig {
const triggerRules = {};
const countMap = {};
const wrapDialogs: { [key: string]: any }[] = [];
@@ -160,10 +161,11 @@ export function createCrossTrainConfig(dialogs: any[], luFiles: string[]): ICros
wrapDialogs.push(parse(dialog));
}
- luFiles = luFiles.map((luFile) => getBaseName(luFile));
+ const luFiles = luIndexer.index(luFilesInfo);
+
//map all referred lu files
luFiles.forEach((file) => {
- countMap[getBaseName(file)] = 1;
+ countMap[getBaseName(file.id)] = 1;
});
let rootId = '';
@@ -174,7 +176,7 @@ export function createCrossTrainConfig(dialogs: any[], luFiles: string[]): ICros
botName = dialog.content.$designer.name;
}
- if (luFiles.find((luFile) => getBaseName(luFile) === dialog.luFile)) {
+ if (luFiles.find((luFile) => getBaseName(luFile.id) === dialog.luFile)) {
const { intentTriggers } = dialog;
const fileId = dialog.id;
//find the trigger's dialog that use a recognizer
diff --git a/Composer/plugins/yarn.lock b/Composer/plugins/yarn.lock
index a8b6d608a7..4739afba37 100644
--- a/Composer/plugins/yarn.lock
+++ b/Composer/plugins/yarn.lock
@@ -181,10 +181,10 @@
passport "^0.4.1"
path-to-regexp "^6.1.0"
-"@microsoft/bf-cli-command@4.10.0-preview.141651":
- version "4.10.0-preview.141651"
- resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-cli-command/-/@microsoft/bf-cli-command-4.10.0-preview.141651.tgz#680875f716285fb8658da8098a0ee524b07c5765"
- integrity sha1-aAh19xYoX7hljagJig7lJLB8V2U=
+"@microsoft/bf-cli-command@4.10.0-dev.20200721.8bb21ac":
+ version "4.10.0-dev.20200721.8bb21ac"
+ resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-cli-command/-/@microsoft/bf-cli-command-4.10.0-dev.20200721.8bb21ac.tgz#9c81b37bc10072ca6beec7d7f68aa309f8a552ec"
+ integrity sha1-nIGze8EAcspr7sfX9oqjCfilUuw=
dependencies:
"@oclif/command" "~1.5.19"
"@oclif/config" "~1.13.3"
@@ -196,10 +196,10 @@
fs-extra "^7.0.1"
tslib "~1.10.0"
-"@microsoft/bf-lu@4.10.0-preview.141651":
- version "4.10.0-preview.141651"
- resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.10.0-preview.141651.tgz#29ed2af803d23ee760354913f5b814873bc1285c"
- integrity sha1-Ke0q+APSPudgNUkT9bgUhzvBKFw=
+"@microsoft/bf-lu@4.10.0-dev.20200721.8bb21ac":
+ version "4.10.0-dev.20200721.8bb21ac"
+ resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.10.0-dev.20200721.8bb21ac.tgz#15c0121fb9e1bf57c18b96de9f4ebcfaeae841fb"
+ integrity sha1-FcASH7nhv1fBi5ben068+uroQfs=
dependencies:
"@azure/cognitiveservices-luis-authoring" "4.0.0-preview.1"
"@azure/ms-rest-azure-js" "2.0.1"
@@ -215,14 +215,15 @@
get-stdin "^6.0.0"
globby "^10.0.1"
intercept-stdout "^0.1.2"
- lodash "^4.17.15"
+ lodash "^4.17.19"
node-fetch "~2.6.0"
semver "^5.5.1"
tslib "^1.10.0"
-"@microsoft/bf-lu@https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/bf-lu/-/@bfcomposer/bf-lu-1.4.0.tgz":
- version "1.4.0"
- resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/bf-lu/-/@bfcomposer/bf-lu-1.4.0.tgz#73314a85637c3eae98aed59fe3c6042b2186f1ae"
+"@microsoft/bf-lu@^4.10.0-dev.20200728.930f45e":
+ version "4.10.0-dev.20200728.930f45e"
+ resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.10.0-dev.20200728.930f45e.tgz#d8a5867d1e3028124b9e0171877b1f063b2bd08e"
+ integrity sha1-2KWGfR4wKBJLngFxh3sfBjsr0I4=
dependencies:
"@azure/cognitiveservices-luis-authoring" "4.0.0-preview.1"
"@azure/ms-rest-azure-js" "2.0.1"
@@ -238,21 +239,21 @@
get-stdin "^6.0.0"
globby "^10.0.1"
intercept-stdout "^0.1.2"
- lodash "^4.17.15"
+ lodash "^4.17.19"
node-fetch "~2.6.0"
semver "^5.5.1"
tslib "^1.10.0"
-"@microsoft/bf-luis-cli@^4.10.0-preview.141651":
- version "4.10.0-preview.141651"
- resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-luis-cli/-/@microsoft/bf-luis-cli-4.10.0-preview.141651.tgz#29ef283f23d9b59841faff4872cb6900b91ec2e8"
- integrity sha1-Ke8oPyPZtZhB+v9IcstpALkewug=
+"@microsoft/bf-luis-cli@^4.10.0-dev.20200721.8bb21ac":
+ version "4.10.0-dev.20200721.8bb21ac"
+ resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-luis-cli/-/@microsoft/bf-luis-cli-4.10.0-dev.20200721.8bb21ac.tgz#b952806f8093dd1639e1141ede9d27ec74b6d379"
+ integrity sha1-uVKAb4CT3RY54RQe3p0n7HS203k=
dependencies:
"@azure/cognitiveservices-luis-authoring" "4.0.0-preview.1"
"@azure/cognitiveservices-luis-runtime" "5.0.0"
"@azure/ms-rest-azure-js" "2.0.1"
- "@microsoft/bf-cli-command" "4.10.0-preview.141651"
- "@microsoft/bf-lu" "4.10.0-preview.141651"
+ "@microsoft/bf-cli-command" "4.10.0-dev.20200721.8bb21ac"
+ "@microsoft/bf-lu" "4.10.0-dev.20200721.8bb21ac"
"@oclif/command" "~1.5.19"
"@oclif/config" "~1.13.3"
"@oclif/errors" "~1.2.2"
@@ -1777,7 +1778,7 @@ lodash.union@^4.6.0:
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
-lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15:
+lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19:
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
diff --git a/Composer/yarn.lock b/Composer/yarn.lock
index 7d7c8053c0..28fb96dabd 100644
--- a/Composer/yarn.lock
+++ b/Composer/yarn.lock
@@ -2929,7 +2929,7 @@
argparse "~1.0.10"
tslib "^1.10.0"
-"@microsoft/bf-lu@4.10.0-preview.141651", "@microsoft/bf-lu@^4.10.0-preview.141651":
+"@microsoft/bf-lu@4.10.0-preview.141651":
version "4.10.0-preview.141651"
resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.10.0-preview.141651.tgz#29ed2af803d23ee760354913f5b814873bc1285c"
integrity sha1-Ke0q+APSPudgNUkT9bgUhzvBKFw=
@@ -2953,9 +2953,10 @@
semver "^5.5.1"
tslib "^1.10.0"
-"@microsoft/bf-lu@https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/bf-lu/-/@bfcomposer/bf-lu-1.4.2.tgz":
- version "1.4.2"
- resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/bf-lu/-/@bfcomposer/bf-lu-1.4.2.tgz#b078f991a65b91471fe667d5571bf5b8bc92d686"
+"@microsoft/bf-lu@^4.10.0-dev.20200728.930f45e":
+ version "4.10.0-dev.20200728.930f45e"
+ resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.10.0-dev.20200728.930f45e.tgz#d8a5867d1e3028124b9e0171877b1f063b2bd08e"
+ integrity sha1-2KWGfR4wKBJLngFxh3sfBjsr0I4=
dependencies:
"@azure/cognitiveservices-luis-authoring" "4.0.0-preview.1"
"@azure/ms-rest-azure-js" "2.0.1"
@@ -2971,30 +2972,7 @@
get-stdin "^6.0.0"
globby "^10.0.1"
intercept-stdout "^0.1.2"
- lodash "^4.17.15"
- node-fetch "~2.6.0"
- semver "^5.5.1"
- tslib "^1.10.0"
-
-"@microsoft/bf-lu@https://botbuilder.myget.org/F/botbuilder-declarative/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-1.3.6.tgz":
- version "1.3.6"
- resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-1.3.6.tgz#69d09da1444a2db06a95d74c9c2fa4599af28f3c"
- dependencies:
- "@azure/cognitiveservices-luis-authoring" "4.0.0-preview.1"
- "@azure/ms-rest-azure-js" "2.0.1"
- "@oclif/command" "~1.5.19"
- "@oclif/errors" "~1.2.2"
- "@types/node-fetch" "~2.5.5"
- antlr4 "^4.7.2"
- chalk "2.4.1"
- console-stream "^0.1.1"
- deep-equal "^1.0.1"
- delay "^4.3.0"
- fs-extra "^8.1.0"
- get-stdin "^6.0.0"
- globby "^10.0.1"
- intercept-stdout "^0.1.2"
- lodash "^4.17.15"
+ lodash "^4.17.19"
node-fetch "~2.6.0"
semver "^5.5.1"
tslib "^1.10.0"
@@ -3677,6 +3655,13 @@
dependencies:
moment ">=2.14.0"
+"@types/moment-timezone@^0.5.13":
+ version "0.5.13"
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/@types/moment-timezone/-/@types/moment-timezone-0.5.13.tgz#0317ccc91eb4c7f4901704166166395c39276528"
+ integrity sha1-AxfMyR60x/SQFwQWYWY5XDknZSg=
+ dependencies:
+ moment ">=2.14.0"
+
"@types/morgan@^1.7.35":
version "1.7.35"
resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.7.35.tgz#6358f502931cc2583d7a94248c41518baa688494"
@@ -4459,6 +4444,25 @@ adaptive-expressions@4.10.0-preview-147186:
moment "^2.25.1"
moment-timezone "^0.5.28"
+adaptive-expressions@4.10.0-preview-150886:
+ version "4.10.0-preview-150886"
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/adaptive-expressions/-/adaptive-expressions-4.10.0-preview-150886.tgz#27d147b8b9389318e1b608601d83f5003701cf7b"
+ integrity sha1-J9FHuLk4kxjhtghgHYP1ADcBz3s=
+ dependencies:
+ "@microsoft/recognizers-text-data-types-timex-expression" "1.1.4"
+ "@types/atob-lite" "^2.0.0"
+ "@types/lru-cache" "^5.1.0"
+ "@types/moment-timezone" "^0.5.13"
+ "@types/xmldom" "^0.1.29"
+ antlr4ts "0.5.0-alpha.3"
+ atob-lite "^2.0.0"
+ big-integer "^1.6.48"
+ jspath "^0.4.0"
+ lodash "^4.17.19"
+ lru-cache "^5.1.1"
+ moment "^2.25.1"
+ moment-timezone "^0.5.28"
+
address@1.0.3, address@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9"
@@ -5536,15 +5540,16 @@ boolean@^3.0.0:
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.1.tgz#35ecf2b4a2ee191b0b44986f14eb5f052a5cbb4f"
integrity sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==
-botbuilder-lg@4.10.0-preview-147186:
- version "4.10.0-preview-147186"
- resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/botbuilder-lg/-/botbuilder-lg-4.10.0-preview-147186.tgz#43ae2290d5264e9920008155a06abb581b5d99aa"
+botbuilder-lg@^4.10.0-preview-150886:
+ version "4.10.0-preview-150886"
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/botbuilder-lg/-/botbuilder-lg-4.10.0-preview-150886.tgz#bbc91011c1c3be3a343acfdb3168f152d71fadc1"
+ integrity sha1-u8kQEcHDvjo0Os/bMWjxUtcfrcE=
dependencies:
- adaptive-expressions "4.10.0-preview-147186"
+ adaptive-expressions "4.10.0-preview-150886"
antlr4ts "0.5.0-alpha.3"
- lodash "^4.17.11"
+ lodash "^4.17.19"
path "^0.12.7"
- uuid "^3.3.3"
+ uuid "^3.4.0"
boxen@^4.2.0:
version "4.2.0"
@@ -8464,8 +8469,8 @@ elegant-spinner@^1.0.1:
elliptic@^6.0.0, elliptic@^6.5.3:
version "6.5.3"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
- integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
+ integrity sha1-y1nrLv2vc6C9eMzXAVpirW4Pk9Y=
dependencies:
bn.js "^4.4.0"
brorand "^1.0.1"
@@ -12400,8 +12405,8 @@ killable@^1.0.1:
kind-of@^2.0.1, kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0, kind-of@^4.0.0, kind-of@^5.0.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
version "6.0.3"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
- integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ integrity sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=
kleur@^3.0.2:
version "3.0.2"
@@ -12825,8 +12830,8 @@ lodash.uniq@^4.5.0:
lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
version "4.17.19"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
- integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
+ integrity sha1-5I3e2+MLMyF4PFtDAfvTU7weSks=
log-driver@^1.2.7:
version "1.2.7"
@@ -13346,8 +13351,8 @@ mixin-object@^2.0.1:
mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.2, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@~0.5.1:
version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
+ integrity sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8=
dependencies:
minimist "^1.2.5"
@@ -16846,8 +16851,8 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
set-value@^0.4.3, set-value@^2.0.0, set-value@^3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-3.0.2.tgz#74e8ecd023c33d0f77199d415409a40f21e61b90"
- integrity sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA==
+ resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/set-value/-/set-value-3.0.2.tgz#74e8ecd023c33d0f77199d415409a40f21e61b90"
+ integrity sha1-dOjs0CPDPQ93GZ1BVAmkDyHmG5A=
dependencies:
is-plain-object "^2.0.4"
@@ -18649,11 +18654,6 @@ uuid@^3.0.0, uuid@^3.2.1, uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
-uuid@^3.3.3:
- version "3.3.3"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
- integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
-
uuid@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"