diff --git a/.github/Tasks/Pull-Request-Commenter/Default/default.txt b/.github/Tasks/Pull-Request-Commenter/Default/default.txt index 40be793728..07c3c7c1fa 100644 --- a/.github/Tasks/Pull-Request-Commenter/Default/default.txt +++ b/.github/Tasks/Pull-Request-Commenter/Default/default.txt @@ -1,5 +1,14 @@ Thank you for raising a pull request. Please ensure you have have completed the following: +#### General - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated the appropriate tests -- [ ] I have updated related documentation \ No newline at end of file +- [ ] I have updated related documentation + +#### Bots +- [ ] I have validated that new and updated responses use appropriate [Speak](https://docs.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-text-to-speech?view=azure-bot-service-3.0) and [InputHint](https://docs.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-add-input-hints?view=azure-bot-service-3.0) properties to ensure a high-quality speech-first experience +- [ ] I have replicated language model changes across the English, French, Italian, German, Spanish, and Chinese `.lu` files and validated that deployment is successful + +#### Deployment Scripts +- [ ] I have replicated my changes in the **Virtual Assistant Template** and **Sample** projects +- [ ] I have replicated my changes in the **Skill Template** and **Sample** projects \ No newline at end of file diff --git a/.github/Tasks/Pull-Request-Commenter/bots.txt b/.github/Tasks/Pull-Request-Commenter/bots.txt deleted file mode 100644 index 47fce714e0..0000000000 --- a/.github/Tasks/Pull-Request-Commenter/bots.txt +++ /dev/null @@ -1,7 +0,0 @@ -Thank you for raising a pull request. Please ensure you have have completed the following: - -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have added or updated the appropriate tests -- [ ] I have updated related documentation -- [ ] I have validated that new and updated responses use appropriate [Speak](https://docs.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-text-to-speech?view=azure-bot-service-3.0) and [InputHint](https://docs.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-add-input-hints?view=azure-bot-service-3.0) properties to ensure a high-quality speech-first experience -- [ ] I have replicated language model changes across the English, French, Italian, German, Spanish, and Chinese `.lu` files and validated that deployment is successful \ No newline at end of file diff --git a/.github/Tasks/Pull-Request-Commenter/default.txt b/.github/Tasks/Pull-Request-Commenter/default.txt deleted file mode 100644 index 40be793728..0000000000 --- a/.github/Tasks/Pull-Request-Commenter/default.txt +++ /dev/null @@ -1,5 +0,0 @@ -Thank you for raising a pull request. Please ensure you have have completed the following: - -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have added or updated the appropriate tests -- [ ] I have updated related documentation \ No newline at end of file diff --git a/.github/Tasks/Pull-Request-Commenter/deployment_scripts.txt b/.github/Tasks/Pull-Request-Commenter/deployment_scripts.txt deleted file mode 100644 index cc44f94ac2..0000000000 --- a/.github/Tasks/Pull-Request-Commenter/deployment_scripts.txt +++ /dev/null @@ -1,6 +0,0 @@ -Thank you for raising a pull request. Please ensure you have have completed the following: - -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have updated related documentation -- [ ] I have replicated my changes in the **Virtual Assistant Template** and **Sample** projects -- [ ] I have replicated my changes in the **Skill Template** and **Sample** projects \ No newline at end of file diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000000..c92263ad0c --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,8 @@ +name-template: v$NEXT_PATCH_VERSION +tag-template: v$NEXT_PATCH_VERSION +branches: + - master +template: | + ## What’s Changed + + $CHANGES diff --git a/docs/reference/knownissues.md b/docs/reference/knownissues.md index a08695029f..c457f5811e 100644 --- a/docs/reference/knownissues.md +++ b/docs/reference/knownissues.md @@ -110,3 +110,14 @@ Then the bot will recreate the state `-documents` when it starts if it doesn't e ## If Visual Studio 2019 Preview is installed, node-gyp cannot find MSBuild.exe This is a known issue with node-gyp: [nodejs/node-gyp#1663](https://github.com/nodejs/node-gyp/issues/1663). Uninstalling Visual Studio 2019 Preview fixes the issue. + +## Botskills CLI tool can't resolve trailing backslash in any of the arguments using Command Prompt as terminal + +There is a known issue in the `Botskills` CLI tool during the command's execution when any of the arguments contains a **trailing backslash** using the `Command Prompt` as terminal. This is due to a parsing issue in the shell. + +Example of the `connect` command with a trailing backslash in the `luisFolder` argument: +``` bash +botskills connect --botName "" --localManifest "" --luisFolder "\" --ts +``` + +So, to avoid this, it's highly recommended to use `PowerShell 6` to execute the CLI tool commands. Also, you can remove the trailing backslash of the argument. diff --git a/lib/typescript/botskills/src/functionality/connectSkill.ts b/lib/typescript/botskills/src/functionality/connectSkill.ts index 2ef7fb8fff..3471a5327d 100644 --- a/lib/typescript/botskills/src/functionality/connectSkill.ts +++ b/lib/typescript/botskills/src/functionality/connectSkill.ts @@ -138,10 +138,10 @@ export class ConnectSkill { // Parse LU file this.logger.message(`Parsing ${luisApp} LU file...`); const ludownParseCommand: string[] = ['ludown', 'parse', 'toluis']; - ludownParseCommand.push(...['--in', luFilePath]); - ludownParseCommand.push(...['--luis_culture', configuration.language]); - ludownParseCommand.push(...['--out_folder', configuration.luisFolder]); - ludownParseCommand.push(...['--out', `"${luisFile}"`]); + ludownParseCommand.push(...[`--in "${luFilePath}"`]); + ludownParseCommand.push(...[`--luis_culture "${configuration.language}"`]); + ludownParseCommand.push(...[`--out_folder "${configuration.luisFolder}"`]); + ludownParseCommand.push(...[`--out "${luisFile}"`]); await this.runCommand(ludownParseCommand, `Parsing ${luisApp} LU file`); diff --git a/lib/typescript/botskills/src/functionality/refreshSkill.ts b/lib/typescript/botskills/src/functionality/refreshSkill.ts index 5d7c938362..3c88fb20d3 100644 --- a/lib/typescript/botskills/src/functionality/refreshSkill.ts +++ b/lib/typescript/botskills/src/functionality/refreshSkill.ts @@ -60,8 +60,8 @@ export class RefreshSkill { const luisgenCommand: string[] = ['luisgen']; luisgenCommand.push(this.dispatchJsonFilePath); - luisgenCommand.push(...[`-${configuration.lgLanguage}`, `"DispatchLuis"`]); - luisgenCommand.push(...['-o', configuration.lgOutFolder]); + luisgenCommand.push(...[`-${configuration.lgLanguage} "DispatchLuis"`]); + luisgenCommand.push(...[`-o "${configuration.lgOutFolder}"`]); await this.runCommand(luisgenCommand, `Executing luisgen for the ${configuration.dispatchName} file`); } catch (err) { diff --git a/skills/src/csharp/automotiveskill/automotiveskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/automotiveskill/automotiveskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/automotiveskill/automotiveskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/automotiveskill/automotiveskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/calendarskill/calendarskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/calendarskill/calendarskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/calendarskill/calendarskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/calendarskill/calendarskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/emailskill/emailskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/emailskill/emailskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/emailskill/emailskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/emailskill/emailskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/experimental/bingsearchskill/bingsearchskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/experimental/bingsearchskill/bingsearchskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/experimental/bingsearchskill/bingsearchskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/experimental/bingsearchskill/bingsearchskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Deployment/Resources/LU/en/news.lu b/skills/src/csharp/experimental/newsskill/Deployment/Resources/LU/en/news.lu index 3d68b5ffe0..78afe0e22c 100644 --- a/skills/src/csharp/experimental/newsskill/Deployment/Resources/LU/en/news.lu +++ b/skills/src/csharp/experimental/newsskill/Deployment/Resources/LU/en/news.lu @@ -19,9 +19,84 @@ - find me news on {topic} - find news on {topic} - news about {topic} +- news about {topic=microsoft} on {site=wsj.com} +- whats the latest news on {site=nytimes.com} +- news on {site=cnn.com} +- latest news on {site} +- find me news about {topic} on {site} +- find me news on {topic} on {site} +- whats the news on {site=cnn.com} +- find news on {topic=technology} on {site=wsj.com} +- whats the latest on {topic} on {site} +- find me news from {site} +- find me news about {topic} from {site} +- {topic} news from {site} +- {topic} news on {site} + +## TrendingArticles +- what's trending now +- what's the latest trending news +- find trending news +- what's the top news on social media +- trending news +- top news on social media +- what news is popular right now +- popular news +- find trending articles +- trending articles +- news trending on social media +- articles popular on social media +- news trending now +- find news trending on social networks +- news popular on social networks +- articles trending now + +## SetFavoriteTopics +- set favorite news topics +- set favorite news categories +- choose favorite news topics +- choose favorite news categories +- set news topics +- set news categories +- set favorites +- choose favorites +- choose my topics +- set my topics +- set news I'm interested in +- choose topics I'm interested in + +## ShowFavoriteTopics +- favorite news +- favorite news topics +- my news categories +- my news topics +- my news interests +- news I'm interested in +- what's my favorite news +- topics I'm interested in +- my news +- my favorite news +- news for me +- my news suggestions +- news topics for me +- what are my favorites +- what are my favorite topics +- find favorites +- find favorite news +- find favorite topics ## None +- 1 +- 2 +- forward email +- find point of interest +- get directions +- add to my to do list +- how long do I have until my next calendar appointment +- hello world +- what's the weather today > # Entity definitions -$topic:simple \ No newline at end of file +$topic:simple +$site:simple \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Deployment/Resources/template.json b/skills/src/csharp/experimental/newsskill/Deployment/Resources/template.json index 0a49db9463..17c59d93de 100644 --- a/skills/src/csharp/experimental/newsskill/Deployment/Resources/template.json +++ b/skills/src/csharp/experimental/newsskill/Deployment/Resources/template.json @@ -70,6 +70,10 @@ "bingServiceName": { "type": "string", "defaultValue": "[concat(parameters('name'), '-bing')]" + }, + "azureMapsServiceName": { + "type": "string", + "defaultValue": "[concat(parameters('name'), '-maps')]" } }, "variables": { @@ -202,6 +206,16 @@ "sku": { "name": "S1" } + }, + { + "type": "Microsoft.Maps/accounts", + "apiVersion": "2018-05-01", + "name": "[parameters('azureMapsServiceName')]", + "location": "global", + "sku": { + "name": "s1", + "tier": "Standard" + } } ], "outputs": { @@ -236,6 +250,10 @@ "bingSearch": { "type": "string", "value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', parameters('bingServiceName')),'2017-04-18').key1]" + }, + "azureMaps": { + "type": "string", + "value": "[listKeys(resourceId('Microsoft.Maps/accounts', parameters('azureMapsServiceName')),'2018-05-01').primaryKey]" } } } \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/experimental/newsskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/experimental/newsskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/experimental/newsskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Dialogs/FavoriteTopicsDialog.cs b/skills/src/csharp/experimental/newsskill/Dialogs/FavoriteTopicsDialog.cs new file mode 100644 index 0000000000..e5c3aaf5bd --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Dialogs/FavoriteTopicsDialog.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Dialogs; +using Microsoft.Bot.Builder.Dialogs.Choices; +using NewsSkill.Models; +using NewsSkill.Responses.FavoriteTopics; +using NewsSkill.Services; + +namespace NewsSkill.Dialogs +{ + public class FavoriteTopicsDialog : NewsDialogBase + { + private NewsClient _client; + private FavoriteTopicsResponses _responder = new FavoriteTopicsResponses(); + + public FavoriteTopicsDialog( + BotSettings settings, + BotServices services, + ConversationState conversationState, + UserState userState, + AzureMapsService mapsService, + IBotTelemetryClient telemetryClient) + : base(nameof(FavoriteTopicsDialog), settings, services, conversationState, userState, mapsService, telemetryClient) + { + TelemetryClient = telemetryClient; + + var newsKey = settings.Properties["BingNewsKey"] ?? throw new Exception("The BingNewsKey must be provided to use this dialog. Please provide this key in your Skill Configuration."); + + _client = new NewsClient(newsKey); + + var favoriteTopics = new WaterfallStep[] + { + GetMarket, + SetMarket, + SetFavorites, + ShowArticles, + }; + + AddDialog(new WaterfallDialog(nameof(FavoriteTopicsDialog), favoriteTopics)); + AddDialog(new ChoicePrompt(nameof(ChoicePrompt))); + AddDialog(new TextPrompt(nameof(TextPrompt), MarketPromptValidatorAsync)); + } + + private async Task SetFavorites(WaterfallStepContext sc, CancellationToken cancellationToken) + { + var convState = await ConvAccessor.GetAsync(sc.Context, () => new NewsSkillState()); + var userState = await UserAccessor.GetAsync(sc.Context, () => new NewsSkillUserState()); + + // if intent is SetFavorites or not set in state yet + if (convState.LuisResult.TopIntent().intent == Luis.newsLuis.Intent.SetFavoriteTopics || userState.Category == null) + { + // show card with categories the user can choose + var categories = new PromptOptions() + { + Choices = new List(), + }; + + categories.Choices.Add(new Choice("Business")); + categories.Choices.Add(new Choice("Entertainment")); + categories.Choices.Add(new Choice("Health")); + categories.Choices.Add(new Choice("Politics")); + categories.Choices.Add(new Choice("World")); + categories.Choices.Add(new Choice("Sports")); + + return await sc.PromptAsync(nameof(ChoicePrompt), new PromptOptions() + { + Prompt = await _responder.RenderTemplate(sc.Context, sc.Context.Activity.Locale, FavoriteTopicsResponses.FavoriteTopicPrompt), + Choices = categories.Choices + }); + } + + return await sc.NextAsync(userState.Category); + } + + private async Task ShowArticles(WaterfallStepContext sc, CancellationToken cancellationToken) + { + var userState = await UserAccessor.GetAsync(sc.Context, () => new NewsSkillUserState()); + + userState.Category = (FoundChoice)sc.Result; + + // show favorite articles + var articles = await _client.GetNewsByCategory(userState.Category.Value, userState.Market); + await _responder.ReplyWith(sc.Context, FavoriteTopicsResponses.ShowArticles, articles); + + return await sc.EndDialogAsync(); + } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Dialogs/FindArticlesDialog.cs b/skills/src/csharp/experimental/newsskill/Dialogs/FindArticlesDialog.cs index e58f6f8b3f..2d1f8dd142 100644 --- a/skills/src/csharp/experimental/newsskill/Dialogs/FindArticlesDialog.cs +++ b/skills/src/csharp/experimental/newsskill/Dialogs/FindArticlesDialog.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder; @@ -18,37 +20,38 @@ public FindArticlesDialog( BotSettings settings, BotServices services, ConversationState conversationState, + UserState userState, + AzureMapsService mapsService, IBotTelemetryClient telemetryClient) - : base(nameof(FindArticlesDialog), services, conversationState, telemetryClient) + : base(nameof(FindArticlesDialog), settings, services, conversationState, userState, mapsService, telemetryClient) { TelemetryClient = telemetryClient; - var key = settings.Properties["BingNewsKey"] ?? throw new Exception("The BingNewsKey must be provided to use this dialog. Please provide this key in your Skill Configuration."); + var newsKey = settings.Properties["BingNewsKey"] ?? throw new Exception("The BingNewsKey must be provided to use this dialog. Please provide this key in your Skill Configuration."); - _client = new NewsClient(key); + _client = new NewsClient(newsKey); var findArticles = new WaterfallStep[] { + GetMarket, + SetMarket, GetQuery, + GetSite, ShowArticles, }; AddDialog(new WaterfallDialog(nameof(FindArticlesDialog), findArticles)); - AddDialog(new TextPrompt(nameof(TextPrompt))); + AddDialog(new TextPrompt(nameof(TextPrompt), MarketPromptValidatorAsync)); } private async Task GetQuery(WaterfallStepContext sc, CancellationToken cancellationToken) { - var state = await Accessor.GetAsync(sc.Context, () => new NewsSkillState()); + var convState = await ConvAccessor.GetAsync(sc.Context, () => new NewsSkillState()); // Let's see if we have a topic - if (state.LuisResult.Entities.topic != null) + if (convState.LuisResult.Entities.topic != null && convState.LuisResult.Entities.topic.Length > 0) { - // If we have a topic let's skip the topic prompt - if (state.LuisResult.Entities.topic.Length > 0) - { - return await sc.NextAsync(state.LuisResult.Entities.topic[0]); - } + return await sc.NextAsync(convState.LuisResult.Entities.topic[0]); } return await sc.PromptAsync(nameof(TextPrompt), new PromptOptions() @@ -57,10 +60,29 @@ private async Task GetQuery(WaterfallStepContext sc, Cancellat }); } + private async Task GetSite(WaterfallStepContext sc, CancellationToken cancellationToken) + { + var convState = await ConvAccessor.GetAsync(sc.Context, () => new NewsSkillState()); + + string query = (string)sc.Result; + + // if site specified in luis, add to query + if (convState.LuisResult.Entities.site != null && convState.LuisResult.Entities.site.Length > 0) + { + string site = convState.LuisResult.Entities.site[0].Replace(" ", string.Empty); + query = string.Concat(query, $" site:{site}"); + } + + return await sc.NextAsync(query); + } + private async Task ShowArticles(WaterfallStepContext sc, CancellationToken cancellationToken) { + var userState = await UserAccessor.GetAsync(sc.Context, () => new NewsSkillUserState()); + var query = (string)sc.Result; - var articles = await _client.GetNewsForTopic(query); + + var articles = await _client.GetNewsForTopic(query, userState.Market); await _responder.ReplyWith(sc.Context, FindArticlesResponses.ShowArticles, articles); return await sc.EndDialogAsync(); diff --git a/skills/src/csharp/experimental/newsskill/Dialogs/MainDialog.cs b/skills/src/csharp/experimental/newsskill/Dialogs/MainDialog.cs index 9290003433..3dc5293930 100644 --- a/skills/src/csharp/experimental/newsskill/Dialogs/MainDialog.cs +++ b/skills/src/csharp/experimental/newsskill/Dialogs/MainDialog.cs @@ -30,6 +30,8 @@ public MainDialog( BotServices services, ConversationState conversationState, FindArticlesDialog findArticlesDialog, + TrendingArticlesDialog trendingArticlesDialog, + FavoriteTopicsDialog favoriteTopicsDialog, IBotTelemetryClient telemetryClient) : base(nameof(MainDialog), telemetryClient) { @@ -42,6 +44,8 @@ public MainDialog( _stateAccessor = _conversationState.CreateProperty(nameof(NewsSkillState)); AddDialog(findArticlesDialog ?? throw new ArgumentNullException(nameof(findArticlesDialog))); + AddDialog(trendingArticlesDialog ?? throw new ArgumentNullException(nameof(trendingArticlesDialog))); + AddDialog(favoriteTopicsDialog ?? throw new ArgumentNullException(nameof(favoriteTopicsDialog))); } protected override async Task OnStartAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken)) @@ -72,6 +76,21 @@ public MainDialog( // switch on general intents switch (intent) { + case newsLuis.Intent.TrendingArticles: + { + // send articles in response + turnResult = await dc.BeginDialogAsync(nameof(TrendingArticlesDialog)); + break; + } + + case newsLuis.Intent.SetFavoriteTopics: + case newsLuis.Intent.ShowFavoriteTopics: + { + // send favorite news categories + turnResult = await dc.BeginDialogAsync(nameof(FavoriteTopicsDialog)); + break; + } + case newsLuis.Intent.FindArticles: { // send greeting response diff --git a/skills/src/csharp/experimental/newsskill/Dialogs/NewsDialogBase.cs b/skills/src/csharp/experimental/newsskill/Dialogs/NewsDialogBase.cs index 830965923f..8a065bf6c5 100644 --- a/skills/src/csharp/experimental/newsskill/Dialogs/NewsDialogBase.cs +++ b/skills/src/csharp/experimental/newsskill/Dialogs/NewsDialogBase.cs @@ -15,22 +15,34 @@ namespace NewsSkill.Dialogs public class NewsDialogBase : ComponentDialog { protected const string LuisResultKey = "LuisResult"; + private MainResponses _responder = new MainResponses(); + private AzureMapsService _mapsService; public NewsDialogBase( string dialogId, + BotSettings settings, BotServices services, ConversationState conversationState, + UserState userState, + AzureMapsService mapsService, IBotTelemetryClient telemetryClient) : base(dialogId) { Services = services; - Accessor = conversationState.CreateProperty(nameof(NewsSkillState)); + ConvAccessor = conversationState.CreateProperty(nameof(NewsSkillState)); + UserAccessor = userState.CreateProperty(nameof(NewsSkillUserState)); TelemetryClient = telemetryClient; + + var mapsKey = settings.Properties["AzureMapsKey"] ?? throw new Exception("The AzureMapsKey must be provided to use this dialog. Please provide this key in your Skill Configuration."); + _mapsService = mapsService; + _mapsService.InitKeyAsync(mapsKey); } protected BotServices Services { get; set; } - protected IStatePropertyAccessor Accessor { get; set; } + protected IStatePropertyAccessor ConvAccessor { get; set; } + + protected IStatePropertyAccessor UserAccessor { get; set; } // This method is called by any waterfall step that throws an exception to ensure consistency public async Task HandleDialogExceptions(WaterfallStepContext sc, Exception ex) @@ -44,16 +56,63 @@ public async Task HandleDialogExceptions(WaterfallStepContext sc, Exc protected override async Task OnBeginDialogAsync(DialogContext dc, object options, CancellationToken cancellationToken = default(CancellationToken)) { - var state = await Accessor.GetAsync(dc.Context); + var state = await ConvAccessor.GetAsync(dc.Context); return await base.OnBeginDialogAsync(dc, options, cancellationToken); } protected override async Task OnContinueDialogAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken)) { - var state = await Accessor.GetAsync(dc.Context); + var state = await ConvAccessor.GetAsync(dc.Context); return await base.OnContinueDialogAsync(dc, cancellationToken); } + + protected async Task GetMarket(WaterfallStepContext sc, CancellationToken cancellationToken) + { + var userState = await UserAccessor.GetAsync(sc.Context, () => new NewsSkillUserState()); + + // Check if there's already a location + if (!string.IsNullOrWhiteSpace(userState.Market)) + { + return await sc.NextAsync(userState.Market); + } + + // Prompt user for location + return await sc.PromptAsync(nameof(TextPrompt), new PromptOptions() + { + Prompt = await _responder.RenderTemplate(sc.Context, sc.Context.Activity.Locale, MainResponses.MarketPrompt), + RetryPrompt = await _responder.RenderTemplate(sc.Context, sc.Context.Activity.Locale, MainResponses.MarketRetryPrompt) + }); + } + + protected async Task SetMarket(WaterfallStepContext sc, CancellationToken cancellationToken) + { + var userState = await UserAccessor.GetAsync(sc.Context, () => new NewsSkillUserState()); + + if (string.IsNullOrWhiteSpace(userState.Market)) + { + string country = (string)sc.Result; + + // use AzureMaps API to get country code from country input by user + userState.Market = await _mapsService.GetCountryCodeAsync(country); + } + + return await sc.NextAsync(); + } + + protected async Task MarketPromptValidatorAsync(PromptValidatorContext promptContext, CancellationToken cancellationToken) + { + var country = promptContext.Recognized.Value; + + // check for valid country code + country = await _mapsService.GetCountryCodeAsync(country); + if (country != null) + { + return await Task.FromResult(true); + } + + return await Task.FromResult(false); + } } } \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Dialogs/TrendingArticlesDialog.cs b/skills/src/csharp/experimental/newsskill/Dialogs/TrendingArticlesDialog.cs new file mode 100644 index 0000000000..bbec5697e5 --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Dialogs/TrendingArticlesDialog.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Dialogs; +using NewsSkill.Models; +using NewsSkill.Responses.TrendingArticles; +using NewsSkill.Services; + +namespace NewsSkill.Dialogs +{ + public class TrendingArticlesDialog : NewsDialogBase + { + private NewsClient _client; + private TrendingArticlesResponses _responder = new TrendingArticlesResponses(); + + public TrendingArticlesDialog( + BotSettings settings, + BotServices services, + ConversationState conversationState, + UserState userState, + AzureMapsService mapsService, + IBotTelemetryClient telemetryClient) + : base(nameof(TrendingArticlesDialog), settings, services, conversationState, userState, mapsService, telemetryClient) + { + TelemetryClient = telemetryClient; + + var key = settings.Properties["BingNewsKey"] ?? throw new Exception("The BingNewsKey must be provided to use this dialog. Please provide this key in your Skill Configuration."); + + _client = new NewsClient(key); + + var trendingArticles = new WaterfallStep[] + { + GetMarket, + SetMarket, + ShowArticles, + }; + + AddDialog(new WaterfallDialog(nameof(TrendingArticlesDialog), trendingArticles)); + AddDialog(new TextPrompt(nameof(TextPrompt), MarketPromptValidatorAsync)); + } + + private async Task ShowArticles(WaterfallStepContext sc, CancellationToken cancellationToken) + { + var userState = await UserAccessor.GetAsync(sc.Context, () => new NewsSkillUserState()); + + var articles = await _client.GetTrendingNews(userState.Market); + await _responder.ReplyWith(sc.Context, TrendingArticlesResponses.ShowArticles, articles); + + return await sc.EndDialogAsync(); + } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/Classification.cs b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/Classification.cs deleted file mode 100644 index df83e9c04e..0000000000 --- a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/Classification.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using Newtonsoft.Json; - -namespace PointOfInterestSkill.Models -{ - public class Classification - { - [JsonProperty(PropertyName = "code")] - public string Code { get; set; } - - [JsonProperty(PropertyName = "names")] - public Name[] Names { get; set; } - } -} \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/Name.cs b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/Name.cs deleted file mode 100644 index 85cb937c0d..0000000000 --- a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/Name.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using Newtonsoft.Json; - -namespace PointOfInterestSkill.Models -{ - public class Name - { - [JsonProperty(PropertyName = "nameLocale")] - public string NameLocale { get; set; } - - [JsonProperty(PropertyName = "name")] - public string NameProperty { get; set; } - } -} \ No newline at end of file diff --git a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchAddress.cs b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchAddress.cs new file mode 100644 index 0000000000..8c72ee5f72 --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchAddress.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace NewsSkill.Models +{ + public class SearchAddress + { + /// + /// Gets or sets a string specifying the country of an address. + /// + /// + /// A string specifying the country of an address. + /// + [JsonProperty(PropertyName = "countryCode")] + public string CountryCode { get; set; } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchResult.cs b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchResult.cs new file mode 100644 index 0000000000..62332da3f3 --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchResult.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace NewsSkill.Models +{ + public class SearchResult + { + /// + /// Gets or sets EntityType string address. + /// + /// + /// The result type. + /// + [JsonProperty(PropertyName = "address")] + public SearchAddress Address { get; set; } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchResultSet.cs b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchResultSet.cs new file mode 100644 index 0000000000..7b07c0f8d1 --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Models/AzureMaps/SearchResultSet.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace NewsSkill.Models +{ + public class SearchResultSet + { + /// + /// Gets or sets the location list. + /// + /// + /// The location list. + /// + [JsonProperty(PropertyName = "results")] + public List Results { get; set; } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Models/NewsSkillUserState.cs b/skills/src/csharp/experimental/newsskill/Models/NewsSkillUserState.cs new file mode 100644 index 0000000000..58d14ed2a4 --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Models/NewsSkillUserState.cs @@ -0,0 +1,15 @@ +using Microsoft.Bot.Builder.Dialogs.Choices; + +namespace NewsSkill.Models +{ + public class NewsSkillUserState + { + public NewsSkillUserState() + { + } + + public FoundChoice Category { get; set; } + + public string Market { get; set; } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Responses/FavoriteTopics/FavoriteTopicsResponses.cs b/skills/src/csharp/experimental/newsskill/Responses/FavoriteTopics/FavoriteTopicsResponses.cs new file mode 100644 index 0000000000..83949b087b --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Responses/FavoriteTopics/FavoriteTopicsResponses.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Azure.CognitiveServices.Search.NewsSearch.Models; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.TemplateManager; +using Microsoft.Bot.Schema; + +namespace NewsSkill.Responses.FavoriteTopics +{ + public class FavoriteTopicsResponses : TemplateManager + { + public const string FavoriteTopicPrompt = "favoriteTopicPrompt"; + public const string ShowArticles = "showArticles"; + + private static LanguageTemplateDictionary _responseTemplates = new LanguageTemplateDictionary + { + ["default"] = new TemplateIdMap + { + { FavoriteTopicPrompt, (context, data) => "What's your favorite news topic?" }, + { ShowArticles, (context, data) => ShowArticleCards(context, data) } + }, + ["en"] = new TemplateIdMap { }, + ["fr"] = new TemplateIdMap { }, + }; + + public FavoriteTopicsResponses() + { + Register(new DictionaryRenderer(_responseTemplates)); + } + + private static object ShowArticleCards(ITurnContext context, dynamic data) + { + var response = context.Activity.CreateReply(); + var articles = data as List; + + if (articles.Any()) + { + response.Text = "Here's what I found on your favorite topic:"; + + if (articles.Count > 1) + { + response.Speak = $"I found a few news stories, here's a summary of the first: {articles[0].Description}"; + } + else + { + response.Speak = $"{articles[0].Description}"; + } + + response.Attachments = new List(); + response.AttachmentLayout = AttachmentLayoutTypes.Carousel; + + foreach (var item in articles) + { + var card = new ThumbnailCard() + { + Title = item.Name, + Subtitle = item.DatePublished, + Text = item.Description, + Images = item?.Image?.Thumbnail?.ContentUrl != null ? new List() + { + new CardImage(item.Image.Thumbnail.ContentUrl), + } + : null, + Buttons = new List() + { + new CardAction(ActionTypes.OpenUrl, title: "Read more", value: item.Url) + }, + }.ToAttachment(); + + response.Attachments.Add(card); + } + } + else + { + response.Text = "Sorry, I couldn't find any articles on that topic."; + response.Speak = "Sorry, I couldn't find any articles on that topic."; + } + + return response; + } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Responses/FindArticles/FindArticlesResponses.cs b/skills/src/csharp/experimental/newsskill/Responses/FindArticles/FindArticlesResponses.cs index 9aaade7049..871a646977 100644 --- a/skills/src/csharp/experimental/newsskill/Responses/FindArticles/FindArticlesResponses.cs +++ b/skills/src/csharp/experimental/newsskill/Responses/FindArticles/FindArticlesResponses.cs @@ -10,6 +10,7 @@ namespace NewsSkill.Responses.FindArticles public class FindArticlesResponses : TemplateManager { public const string TopicPrompt = "topicPrompt"; + public const string MarketPrompt = "marketPrompt"; public const string ShowArticles = "showArticles"; private static LanguageTemplateDictionary _responseTemplates = new LanguageTemplateDictionary @@ -17,6 +18,7 @@ public class FindArticlesResponses : TemplateManager ["default"] = new TemplateIdMap { { TopicPrompt, (context, data) => "What topic are you interested in?" }, + { MarketPrompt, (context, data) => "What country do you want to search in?" }, { ShowArticles, (context, data) => ShowArticleCards(context, data) } }, ["en"] = new TemplateIdMap { }, diff --git a/skills/src/csharp/experimental/newsskill/Responses/Main/MainResponses.cs b/skills/src/csharp/experimental/newsskill/Responses/Main/MainResponses.cs index 56088065d4..013637ca64 100644 --- a/skills/src/csharp/experimental/newsskill/Responses/Main/MainResponses.cs +++ b/skills/src/csharp/experimental/newsskill/Responses/Main/MainResponses.cs @@ -17,6 +17,8 @@ public class MainResponses : TemplateManager public const string Greeting = "greeting"; public const string Help = "help"; public const string Intro = "intro"; + public const string MarketPrompt = "marketPrompt"; + public const string MarketRetryPrompt = "marketRetryPrompt"; private static LanguageTemplateDictionary _responseTemplates = new LanguageTemplateDictionary { @@ -28,6 +30,8 @@ public class MainResponses : TemplateManager { Greeting, (context, data) => MainStrings.GREETING }, { Help, (context, data) => SendHelpCard(context, data) }, { Intro, (context, data) => SendIntroCard(context, data) }, + { MarketPrompt, (context, data) => "What country do you want to search in?" }, + { MarketRetryPrompt, (context, data) => "Couldn't find that country. What country do you want to search in?" } }, ["en"] = new TemplateIdMap { }, ["fr"] = new TemplateIdMap { }, diff --git a/skills/src/csharp/experimental/newsskill/Responses/TrendingArticles/TrendingArticlesResponses.cs b/skills/src/csharp/experimental/newsskill/Responses/TrendingArticles/TrendingArticlesResponses.cs new file mode 100644 index 0000000000..006fa8a0bf --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Responses/TrendingArticles/TrendingArticlesResponses.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Azure.CognitiveServices.Search.NewsSearch.Models; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.TemplateManager; +using Microsoft.Bot.Schema; + +namespace NewsSkill.Responses.TrendingArticles +{ + public class TrendingArticlesResponses : TemplateManager + { + public const string ShowArticles = "showArticles"; + public const string MarketPrompt = "marketPrompt"; + + private static LanguageTemplateDictionary _responseTemplates = new LanguageTemplateDictionary + { + ["default"] = new TemplateIdMap + { + { MarketPrompt, (context, data) => "What country are you in?" }, + { ShowArticles, (context, data) => ShowArticleCards(context, data) } + }, + ["en"] = new TemplateIdMap { }, + ["fr"] = new TemplateIdMap { }, + }; + + public TrendingArticlesResponses() + { + Register(new DictionaryRenderer(_responseTemplates)); + } + + private static object ShowArticleCards(ITurnContext context, dynamic data) + { + var response = context.Activity.CreateReply(); + var articles = data as List; + + if (articles.Any()) + { + response.Text = "Here's what's trending:"; + + if (articles.Count > 1) + { + response.Speak = $"I found a few news stories, here's the title of the first: {articles[0].Name}"; + } + else + { + response.Speak = $"{articles[0].Description}"; + } + + response.Attachments = new List(); + response.AttachmentLayout = AttachmentLayoutTypes.Carousel; + + foreach (var item in articles) + { + var card = new HeroCard() + { + Title = item.Name, + Images = item?.Image?.Url != null ? new List() + { + new CardImage(item.Image.Url), + } + : null, + Buttons = new List() + { + new CardAction(ActionTypes.OpenUrl, title: "Read more", value: item.WebSearchUrl) + }, + }.ToAttachment(); + + response.Attachments.Add(card); + } + } + else + { + response.Text = "Sorry, I couldn't find any trending articles."; + response.Speak = "Sorry, I couldn't find any trending articles."; + } + + return response; + } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Services/AzureMapsService.cs b/skills/src/csharp/experimental/newsskill/Services/AzureMapsService.cs new file mode 100644 index 0000000000..5dabbab6c8 --- /dev/null +++ b/skills/src/csharp/experimental/newsskill/Services/AzureMapsService.cs @@ -0,0 +1,46 @@ +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using NewsSkill.Models; +using Newtonsoft.Json; + +namespace NewsSkill.Services +{ + public sealed class AzureMapsService + { + private const string FuzzyQueryApiUrl = "https://atlas.microsoft.com/search/fuzzy/json?api-version=1.0&query={0}"; + private static string apiKey; + private static HttpClient httpClient = new HttpClient(); + + public void InitKeyAsync(string key) + { + // set user's api key + apiKey = key; + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + } + + public async Task GetCountryCodeAsync(string query) + { + if (string.IsNullOrEmpty(query)) + { + throw new ArgumentNullException(nameof(query)); + } + + // add query and key to api url + var url = string.Format(FuzzyQueryApiUrl, query); + url = string.Concat(url, $"&subscription-key={apiKey}"); + + var response = await httpClient.GetStringAsync(url); + var apiResponse = JsonConvert.DeserializeObject(response); + + // check there is a valid response + if (apiResponse != null && apiResponse.Results.Count > 0) + { + return apiResponse.Results[0]?.Address?.CountryCode; + } + + return null; + } + } +} diff --git a/skills/src/csharp/experimental/newsskill/Services/NewsClient.cs b/skills/src/csharp/experimental/newsskill/Services/NewsClient.cs index 6aada40178..cc14d85b6f 100644 --- a/skills/src/csharp/experimental/newsskill/Services/NewsClient.cs +++ b/skills/src/csharp/experimental/newsskill/Services/NewsClient.cs @@ -14,15 +14,25 @@ public NewsClient(string key) _client = new NewsSearchClient(new ApiKeyServiceClientCredentials(key)); } - public async Task> GetNewsForTopic(string query) + public async Task> GetNewsForTopic(string query, string mkt) { - var results = await _client.News.SearchAsync(query, market: "en-us", count: 10); + // general search by topic + var results = await _client.News.SearchAsync(query, countryCode: mkt, count: 10); return results.Value; } - public async Task> GetTrendingNews() + public async Task> GetTrendingNews(string mkt) { - var results = await _client.News.TrendingAsync(market: "en-us", count: 10); + // get articles trending on social media + var results = await _client.News.TrendingAsync(countryCode: mkt, count: 10); + return results.Value; + } + + // see for valid categories: https://docs.microsoft.com/en-us/rest/api/cognitiveservices-bingsearch/bing-news-api-v7-reference#news-categories-by-market + public async Task> GetNewsByCategory(string topic, string mkt) + { + // general search by category + var results = await _client.News.CategoryAsync(category: topic, market: mkt, count: 10); return results.Value; } } diff --git a/skills/src/csharp/experimental/newsskill/Services/NewsLuis.cs b/skills/src/csharp/experimental/newsskill/Services/NewsLuis.cs index 68d9709b92..4c76b62d06 100644 --- a/skills/src/csharp/experimental/newsskill/Services/NewsLuis.cs +++ b/skills/src/csharp/experimental/newsskill/Services/NewsLuis.cs @@ -16,6 +16,9 @@ public class newsLuis: IRecognizerConvert public string AlteredText; public enum Intent { FindArticles, + TrendingArticles, + SetFavoriteTopics, + ShowFavoriteTopics, None }; public Dictionary Intents; @@ -24,11 +27,13 @@ public class _Entities { // Simple entities public string[] topic; + public string[] site; // Instance public class _Instance { public InstanceData[] topic; + public InstanceData[] site; } [JsonProperty("$instance")] public _Instance _instance; diff --git a/skills/src/csharp/experimental/newsskill/Startup.cs b/skills/src/csharp/experimental/newsskill/Startup.cs index 3a25c8940d..62a0975647 100644 --- a/skills/src/csharp/experimental/newsskill/Startup.cs +++ b/skills/src/csharp/experimental/newsskill/Startup.cs @@ -89,12 +89,17 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddHostedService(); + // Configure Azure maps services + services.AddSingleton(); + // Configure HttpContext required for path resolution services.AddSingleton(); // register dialogs services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); // Configure adapters services.AddTransient(); diff --git a/skills/src/csharp/experimental/newsskill/appsettings.json b/skills/src/csharp/experimental/newsskill/appsettings.json index 1146d6b35c..c6fc894418 100644 --- a/skills/src/csharp/experimental/newsskill/appsettings.json +++ b/skills/src/csharp/experimental/newsskill/appsettings.json @@ -16,6 +16,7 @@ "authKey": "" }, "properties": { - "BingNewsKey": "" + "BingNewsKey": "", + "AzureMapsKey": "" } } \ No newline at end of file diff --git a/skills/src/csharp/experimental/restaurantbooking/Deployment/Scripts/publish.ps1 b/skills/src/csharp/experimental/restaurantbooking/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/experimental/restaurantbooking/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/experimental/restaurantbooking/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/experimental/weatherskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/experimental/weatherskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/experimental/weatherskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/experimental/weatherskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/pointofinterestskill/pointofinterestskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/pointofinterestskill/pointofinterestskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/pointofinterestskill/pointofinterestskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/pointofinterestskill/pointofinterestskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/skills/src/csharp/todoskill/todoskill/Deployment/Scripts/publish.ps1 b/skills/src/csharp/todoskill/todoskill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/skills/src/csharp/todoskill/todoskill/Deployment/Scripts/publish.ps1 +++ b/skills/src/csharp/todoskill/todoskill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/BaseActivity.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/BaseActivity.java index 2daee7f0e1..786eef630b 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/BaseActivity.java +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/BaseActivity.java @@ -36,6 +36,7 @@ public abstract class BaseActivity extends AppCompatActivity { private static final Integer PERMISSION_REQUEST_FINE_LOCATION = 102; private static final String SHARED_PREFS_NAME = "my_shared_prefs"; protected static final String SHARED_PREF_SHOW_TEXTINPUT = "SHARED_PREF_SHOW_TEXTINPUT"; + protected static final String SHARED_PREF_SHOW_FULL_CONVERSATION = "SHARED_PREF_SHOW_FULL_CONVERSATION"; // State private SharedPreferences sharedPreferences; diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/MainActivity.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/MainActivity.java index 74a2091657..cc2f6b17de 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/MainActivity.java +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/MainActivity.java @@ -42,7 +42,7 @@ import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.actionslist.ActionsAdapter; import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.actionslist.ActionsViewholder; import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist.ChatAdapter; -import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist.ChatViewholder; +import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist.ViewholderBot; import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist.ItemOffsetDecoration; import com.microsoft.bot.builder.solutions.virtualassistant.assistant.VoiceInteractionActivity; @@ -69,7 +69,7 @@ import events.RequestTimeout; public class MainActivity extends BaseActivity - implements NavigationView.OnNavigationItemSelectedListener, ChatViewholder.OnClickListener, ActionsViewholder.OnClickListener { + implements NavigationView.OnNavigationItemSelectedListener, ViewholderBot.OnClickListener, ActionsViewholder.OnClickListener { // VIEWS @BindView(R.id.root_container) RelativeLayout uiContainer; @@ -80,6 +80,7 @@ public class MainActivity extends BaseActivity @BindView(R.id.drawer_layout) DrawerLayout drawer; @BindView(R.id.nav_view) NavigationView navigationView; @BindView(R.id.switch_show_textinput) SwitchCompat switchShowTextInput; + @BindView(R.id.switch_show_full_conversation) SwitchCompat switchShowFullConversation; @BindView(R.id.speech_detection) TextView detectedSpeechToText; @BindView(R.id.agent_image) ImageView agentImage; @@ -91,9 +92,11 @@ public class MainActivity extends BaseActivity private ChatAdapter chatAdapter; private ActionsAdapter suggActionsAdapter; private boolean alwaysShowTextInput; + private boolean showFullConversation; private Handler handler; private boolean launchedAsAssistant; private Gson gson; + private SfxManager sfxManager; @Override protected void onCreate(Bundle savedInstanceState) { @@ -104,9 +107,14 @@ protected void onCreate(Bundle savedInstanceState) { handler = new Handler(Looper.getMainLooper()); gson = new Gson(); + setupChatRecyclerView(); + setupSuggestedActionsRecyclerView(); + // Options hidden in the nav-drawer alwaysShowTextInput = getBooleanSharedPref(SHARED_PREF_SHOW_TEXTINPUT); switchShowTextInput.setChecked(alwaysShowTextInput); + showFullConversation = getBooleanSharedPref(SHARED_PREF_SHOW_FULL_CONVERSATION); + switchShowFullConversation.setChecked(showFullConversation); // NAV DRAWER ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, R.string.navigation_drawer_open, R.string.navigation_drawer_close); @@ -126,9 +134,6 @@ protected void onCreate(Bundle savedInstanceState) { // make media volume the default setVolumeControlStream(AudioManager.STREAM_MUSIC); - setupChatRecyclerView(); - setupSuggestedActionsRecyclerView(); - // check if this activity was launched as an assistant Intent intent = getIntent(); if (intent != null) { @@ -138,6 +143,8 @@ protected void onCreate(Bundle savedInstanceState) { } } + sfxManager = new SfxManager(); + sfxManager.initialize(this); } // Register for EventBus messages and SpeechService @@ -284,6 +291,7 @@ public boolean onNavigationItemSelected(MenuItem item) { public void onAssistantClick() { try { showSnackbar(uiContainer, getString(R.string.msg_listening)); + sfxManager.playEarconListening(); speechServiceBinder.listenOnceAsync(); } catch (RemoteException exception){ Log.e(LOGTAG, exception.getMessage()); @@ -300,6 +308,13 @@ public void OnShowTextInput(CompoundButton button, boolean checked){ textInputLayout.setVisibility(View.GONE); } + @OnCheckedChanged(R.id.switch_show_full_conversation) + public void OnShowFullConversation(CompoundButton button, boolean checked){ + showFullConversation = checked; + putBooleanSharedPref(SHARED_PREF_SHOW_FULL_CONVERSATION, checked); + chatAdapter.setShowFullConversation(showFullConversation); + } + @OnEditorAction(R.id.textinput) boolean onEditorAction(int actionId, KeyEvent key){ boolean handled = false; @@ -314,9 +329,19 @@ boolean onEditorAction(int actionId, KeyEvent key){ // send text message private void sendTextMessage(String msg){ + if (msg == null || msg.length() == 0) return; + try { + // add the users' request to the chat + chatAdapter.addUserRequest(msg); + // make the chat list scroll automatically after adding a bot response + chatRecyclerView.getLayoutManager().scrollToPosition(chatAdapter.getItemCount() - 1); + + // send request to Bot speechServiceBinder.sendActivityMessageAsync(msg); + sfxManager.playEarconProcessing(); + // clear out suggested actions String json = speechServiceBinder.getSuggestedActions(); List list = gson.fromJson(json, new TypeToken>(){}.getType()); @@ -355,6 +380,7 @@ public void onEventRecognizedIntermediateResult(RecognizedIntermediateResult eve // EventBus: the user spoke and the app recognized the speech. Disconnect mic. @Subscribe(threadMode = ThreadMode.MAIN) public void onEventRecognized(Recognized event) { + sfxManager.playEarconDoneListening(); detectedSpeechToText.setText(event.recognized_speech); // in 2 seconds clear the text (at this point the bot should be giving its' response) handler.postDelayed(() -> detectedSpeechToText.setText(""), 2000); @@ -365,6 +391,7 @@ public void onEventRecognized(Recognized event) { public void onEventActivityReceived(ActivityReceived activityReceived) throws IOException { if (activityReceived.botConnectorActivity != null) { BotConnectorActivity botConnectorActivity = activityReceived.botConnectorActivity; + sfxManager.playEarconResults(); switch (botConnectorActivity.getType()) { case "message": @@ -379,7 +406,7 @@ public void onEventActivityReceived(ActivityReceived activityReceived) throws IO } } - chatAdapter.addChat(botConnectorActivity, this, this); + chatAdapter.addBotResponse(botConnectorActivity, this, this); // make the chat list scroll automatically after adding a bot response chatRecyclerView.getLayoutManager().scrollToPosition(chatAdapter.getItemCount() - 1); @@ -401,6 +428,7 @@ public void onEventActivityReceived(ActivityReceived activityReceived) throws IO @Subscribe(threadMode = ThreadMode.MAIN) public void onEventRequestTimeout(RequestTimeout event) { // here you can notify the user to repeat the request + sfxManager.playEarconDisambigError(); } private void playMediaStream(String mediaStream) { @@ -424,7 +452,7 @@ public void adaptiveCardClick(int position, String speak) { try { String json = speechServiceBinder.getSuggestedActions(); List list = gson.fromJson(json, new TypeToken>(){}.getType()); - if (list != null){ + if (list != null && list.size() > position){ cardAction = list.get(position); } } catch (RemoteException exception){ @@ -438,6 +466,8 @@ public void adaptiveCardClick(int position, String speak) { } else { sendTextMessage(speak); } + + sfxManager.playEarconProcessing(); } // concrete implementation of ActionsViewholder.OnClickListener @@ -458,6 +488,7 @@ public void suggestedActionClick(int position) { if (cardAction != null) { String value = (String) cardAction.getValue(); sendTextMessage(value); + sfxManager.playEarconProcessing(); } } diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/SfxManager.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/SfxManager.java new file mode 100644 index 0000000000..7ba9af9edc --- /dev/null +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/SfxManager.java @@ -0,0 +1,88 @@ +package com.microsoft.bot.builder.solutions.virtualassistant.activities.main; + +import android.content.Context; +import android.media.AudioAttributes; +import android.media.SoundPool; +import android.util.Log; + +import com.microsoft.bot.builder.solutions.virtualassistant.R; + +/** + * Sound-effect Manager + * + * How it works: + * 1. sound is loaded + * 2. onLoadComplete triggers playing the sound + */ +public class SfxManager implements SoundPool.OnLoadCompleteListener{ + + // CONSTANTS + private final String LOGTAG = getClass().getSimpleName(); + private final static int MAX_SIMULTANEOUS_SFX = 10; + private final static float PLAY_RATE = 1.0f; + private final static float VOLUME = 0.5f; + + // STATE + private SoundPool mSoundPool; + private Context context; + + public SfxManager initialize(Context context){ + this.context = context; + initSoundPool(); + return this; + } + + private void initSoundPool(){ + AudioAttributes audioAttributes = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .setUsage(AudioAttributes.USAGE_GAME) + .build(); + mSoundPool = new SoundPool.Builder() + .setMaxStreams(MAX_SIMULTANEOUS_SFX) + .setAudioAttributes(audioAttributes) + .build(); + mSoundPool.setOnLoadCompleteListener(this); + } + + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + if (status == 0) { + Log.d(LOGTAG, "playing Sound effect sampleID: " + sampleId); + int streamID = soundPool.play(sampleId, VOLUME, VOLUME, 1, 0, PLAY_RATE); + } else { + Log.d(LOGTAG, "loading failed, status: " + status); + } + } + + /** + * Play a sound in its own MediaPlayer on its own thread + * @param resRawId + * @return the sound id + */ + private int playSfx(int resRawId) { + final int soundId = mSoundPool.load(context, resRawId, 1); + return soundId; + } + + + + public void playEarconDisambigError() { + playSfx(R.raw.earcon_disambig_error); + } + + public void playEarconDoneListening() { + playSfx(R.raw.earcon_done_listening); + } + + public void playEarconListening() { + playSfx(R.raw.earcon_listening); + } + + public void playEarconProcessing() { + playSfx(R.raw.earcon_processing); + } + + public void playEarconResults() { + playSfx(R.raw.earcon_results); + } +} diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatAdapter.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatAdapter.java index 307eb672dd..6c2861d8c8 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatAdapter.java +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatAdapter.java @@ -11,34 +11,59 @@ import com.microsoft.bot.builder.solutions.virtualassistant.R; import java.util.ArrayList; -import java.util.List; import client.model.BotConnectorActivity; -public class ChatAdapter extends RecyclerView.Adapter { +public class ChatAdapter extends RecyclerView.Adapter { // CONSTANTS - private final int CONTENT_VIEW = R.layout.item_chat; private static final String LOGTAG = "ChatAdapter"; + private static final int MSG_TYPE_BOT = 1; + private static final int MSG_TYPE_USER = 2; // STATE - private ArrayList chatList = new ArrayList<>(); + private ArrayList chatList = new ArrayList<>(); private AppCompatActivity parentActivity; - private ChatViewholder.OnClickListener clickListener; - private static int MAX_CHAT_ITEMS = 1; + private ViewholderBot.OnClickListener clickListener; + private static int MAX_CHAT_ITEMS = 2; + private boolean showFullConversation; @NonNull @Override - public ChatViewholder onCreateViewHolder(@NonNull ViewGroup parent, int i) { - View view = LayoutInflater.from(parent.getContext()).inflate(CONTENT_VIEW, parent, false); - return new ChatViewholder(view); + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + RecyclerView.ViewHolder viewHolder = null; + + if (viewType == MSG_TYPE_BOT) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_bot, parent, false); + viewHolder = new ViewholderBot(view); + } + if (viewType == MSG_TYPE_USER) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_user, parent, false); + viewHolder = new ViewholderUser(view); + } + + return viewHolder; + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + ChatModel chatModel = chatList.get(position); + if (getItemViewType(position) == MSG_TYPE_BOT) { + ((ViewholderBot)viewHolder).bind(chatModel, parentActivity, clickListener); + } + if (getItemViewType(position) == MSG_TYPE_USER) { + ((ViewholderUser)viewHolder).bind(chatModel, parentActivity); + } } @Override - public void onBindViewHolder(@NonNull ChatViewholder chatViewholder, int position) { - BotConnectorActivity botConnectorActivity = chatList.get(position); - chatViewholder.bind(botConnectorActivity, parentActivity, clickListener); + public int getItemViewType(int position) { + ChatModel chatModel = chatList.get(position); + if (chatModel.userRequest != null) + return MSG_TYPE_USER; + else + return MSG_TYPE_BOT; } @Override @@ -47,17 +72,35 @@ public int getItemCount() { return chatList.size(); } - public void addChat(BotConnectorActivity botConnectorActivity, AppCompatActivity parentActivity, ChatViewholder.OnClickListener clickListener) { + public void setShowFullConversation(boolean showFullConversation){ + this.showFullConversation = showFullConversation; + chatList.clear(); + notifyDataSetChanged(); + } + + public void addBotResponse(BotConnectorActivity botConnectorActivity, AppCompatActivity parentActivity, ViewholderBot.OnClickListener clickListener) { Log.v(LOGTAG, "showing row id "+ botConnectorActivity.getId()); this.parentActivity = parentActivity; this.clickListener = clickListener; - chatList.add(botConnectorActivity); + ChatModel chatModel = new ChatModel(botConnectorActivity); + chatList.add(chatModel); if (chatList.size() > MAX_CHAT_ITEMS) { chatList.remove(0); } notifyDataSetChanged(); } + public void addUserRequest(String request) { + if (showFullConversation) { + ChatModel chatModel = new ChatModel(request); + chatList.add(chatModel); + if (chatList.size() > MAX_CHAT_ITEMS) { + chatList.remove(0); + } + notifyDataSetChanged(); + } + } + public void setChatItemHistoryCount(int count){ MAX_CHAT_ITEMS = count; while (chatList.size() > MAX_CHAT_ITEMS) { @@ -65,10 +108,4 @@ public void setChatItemHistoryCount(int count){ } notifyDataSetChanged(); } - - public void swapChatList(List newChatList) { - chatList.clear(); - chatList.addAll(newChatList); - notifyDataSetChanged(); - } } diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatModel.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatModel.java new file mode 100644 index 0000000000..03b8e40806 --- /dev/null +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatModel.java @@ -0,0 +1,16 @@ +package com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist; + +import client.model.BotConnectorActivity; + +public class ChatModel { + public BotConnectorActivity botConnectorActivity; + public String userRequest; + + public ChatModel(BotConnectorActivity botConnectorActivity) { + this.botConnectorActivity = botConnectorActivity; + } + + public ChatModel(String userRequest) { + this.userRequest = userRequest; + } +} diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatViewholder.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ViewholderBot.java similarity index 87% rename from solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatViewholder.java rename to solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ViewholderBot.java index 144f1691f5..2d4f8d3ba7 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ChatViewholder.java +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ViewholderBot.java @@ -27,13 +27,13 @@ import io.adaptivecards.renderer.AdaptiveCardRenderer; import io.adaptivecards.renderer.RenderedAdaptiveCard; -public class ChatViewholder extends RecyclerView.ViewHolder { +public class ViewholderBot extends RecyclerView.ViewHolder { // CONSTANTS private static final String LOGTAG = "ChatViewholder"; // VIEWS - @BindView(R.id.tv_bot_chat) TextView textMessage; + @BindView(R.id.tv_chat) TextView textMessage; @BindView(R.id.adaptive_card_container) LinearLayout adaptiveCardLayout; // STATE @@ -44,7 +44,7 @@ public interface OnClickListener { void adaptiveCardClick(int position, String speak); } - public ChatViewholder(@NonNull View itemView) { + public ViewholderBot(@NonNull View itemView) { super(itemView); view = itemView; ButterKnife.bind(this, view); @@ -53,13 +53,14 @@ public ChatViewholder(@NonNull View itemView) { /** * bind the layout with the data - * @param botConnectorActivity data + * @param ChatModel chatModel */ - void bind(@NonNull BotConnectorActivity botConnectorActivity, AppCompatActivity parentActivity, @NonNull OnClickListener onClickListener) { + void bind(@NonNull ChatModel chatModel, AppCompatActivity parentActivity, @NonNull OnClickListener onClickListener) { + BotConnectorActivity botConnectorActivity = chatModel.botConnectorActivity; textMessage.setText(botConnectorActivity.getText()); - if (botConnectorActivity.getAttachmentLayout() != null && botConnectorActivity.getAttachments().size() > 0){ - if (botConnectorActivity.getAttachmentLayout().equals("carousel") || botConnectorActivity.getAttachmentLayout().equals("list")){ + if (botConnectorActivity.getAttachmentLayout() != null && botConnectorActivity.getAttachments().size() > 0) { + if (botConnectorActivity.getAttachmentLayout().equals("carousel") || botConnectorActivity.getAttachmentLayout().equals("list")) { Gson gson = new GsonBuilder().disableHtmlEscaping().create(); adaptiveCardLayout.setVisibility(View.VISIBLE); @@ -99,10 +100,9 @@ void bind(@NonNull BotConnectorActivity botConnectorActivity, AppCompatActivity // add the cards to the existing layout to make them visible adaptiveCardLayout.addView(itemAdaptiveCard); - Log.d(LOGTAG, "renderedAdaptiveCard warnings: "+renderedCard.getWarnings().size() + " " + renderedCard.getWarnings().toString()); - } - catch (Exception ex) { - Log.e(LOGTAG,"Error in json: " + ex.getMessage()); + Log.d(LOGTAG, "renderedAdaptiveCard warnings: " + renderedCard.getWarnings().size() + " " + renderedCard.getWarnings().toString()); + } catch (Exception ex) { + Log.e(LOGTAG, "Error in json: " + ex.getMessage()); } } } diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ViewholderUser.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ViewholderUser.java new file mode 100644 index 0000000000..545cdcc838 --- /dev/null +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/chatlist/ViewholderUser.java @@ -0,0 +1,53 @@ +package com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist; + +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.CardView; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.microsoft.bot.builder.solutions.virtualassistant.R; +import com.microsoft.bot.builder.solutions.virtualassistant.utils.LogUtils; +import com.microsoft.bot.builder.solutions.virtualassistant.utils.RawUtils; + +import org.json.JSONObject; + +import butterknife.BindView; +import butterknife.ButterKnife; +import client.model.BotConnectorActivity; +import io.adaptivecards.objectmodel.AdaptiveCard; +import io.adaptivecards.objectmodel.HostConfig; +import io.adaptivecards.objectmodel.ParseResult; +import io.adaptivecards.renderer.AdaptiveCardRenderer; +import io.adaptivecards.renderer.RenderedAdaptiveCard; + +public class ViewholderUser extends RecyclerView.ViewHolder { + + // CONSTANTS + private static final String LOGTAG = "ChatViewholder"; + + // VIEWS + @BindView(R.id.tv_chat) TextView textMessage; + + // STATE + private View view; + + public ViewholderUser(@NonNull View itemView) { + super(itemView); + view = itemView; + ButterKnife.bind(this, view); + } + + /** + * bind the layout with the data + */ + void bind(@NonNull ChatModel chatModel, AppCompatActivity parentActivity) { + textMessage.setText(chatModel.userRequest); + } +} \ No newline at end of file diff --git a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/service/SpeechService.java b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/service/SpeechService.java index 45be71582e..4b76d71ddf 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/service/SpeechService.java +++ b/solutions/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/service/SpeechService.java @@ -13,6 +13,7 @@ import android.graphics.BitmapFactory; import android.graphics.Color; import android.media.MediaPlayer; +import android.net.Uri; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; @@ -367,6 +368,10 @@ public void onEventActivityReceived(ActivityReceived activityReceived) throws IO Log.i(TAG_FOREGROUND_SERVICE, "Activity with PlayLocalFile"); playMediaStream(botConnectorActivity.getFile()); break; + case "OpenDefaultApp": + Log.i(TAG_FOREGROUND_SERVICE, "OpenDefaultApp"); + openDefaultApp(botConnectorActivity); + break; default: break; } @@ -383,7 +388,25 @@ private void playMediaStream(String mediaStream) { catch(IOException e) { Log.e(TAG_FOREGROUND_SERVICE, "IOexception " + e.getMessage()); } + } + private void openDefaultApp(BotConnectorActivity botConnectorActivity){ + String intentStr = botConnectorActivity.getText(); + if (intentStr.startsWith("geo")){ + Uri intentUri = Uri.parse(intentStr); + Intent mapIntent = new Intent(Intent.ACTION_VIEW, intentUri); + mapIntent.setPackage("com.google.android.apps.maps"); + if (mapIntent.resolveActivity(getPackageManager()) != null) { + startActivity(mapIntent); + } + } + if (intentStr.startsWith("tel")){ + Uri intentUri = Uri.parse(intentStr); + Intent dialerIntent = new Intent(Intent.ACTION_DIAL, intentUri); + if (dialerIntent.resolveActivity(getPackageManager()) != null) { + startActivity(dialerIntent); + } + } } private void broadcastActivity(BotConnectorActivity botConnectorActivity){ diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/layout/activity_main.xml b/solutions/android/VirtualAssistantClient/app/src/main/res/layout/activity_main.xml index 9d7ec93994..f6d16f722e 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/res/layout/activity_main.xml +++ b/solutions/android/VirtualAssistantClient/app/src/main/res/layout/activity_main.xml @@ -103,6 +103,13 @@ android:layout_marginLeft="14dp" android:orientation="vertical"> + + - - - - - - - - - - - - - - - - - - - - diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/layout/item_chat_bot.xml b/solutions/android/VirtualAssistantClient/app/src/main/res/layout/item_chat_bot.xml new file mode 100644 index 0000000000..77748e8fc1 --- /dev/null +++ b/solutions/android/VirtualAssistantClient/app/src/main/res/layout/item_chat_bot.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/layout/item_chat_user.xml b/solutions/android/VirtualAssistantClient/app/src/main/res/layout/item_chat_user.xml new file mode 100644 index 0000000000..dd0584caf4 --- /dev/null +++ b/solutions/android/VirtualAssistantClient/app/src/main/res/layout/item_chat_user.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_disambig_error.wav b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_disambig_error.wav new file mode 100644 index 0000000000..a712189e78 Binary files /dev/null and b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_disambig_error.wav differ diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_done_listening.wav b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_done_listening.wav new file mode 100644 index 0000000000..410b1f7092 Binary files /dev/null and b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_done_listening.wav differ diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_listening.wav b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_listening.wav new file mode 100644 index 0000000000..a580a85bd9 Binary files /dev/null and b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_listening.wav differ diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_processing.wav b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_processing.wav new file mode 100644 index 0000000000..9d202b35f6 Binary files /dev/null and b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_processing.wav differ diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_results.wav b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_results.wav new file mode 100644 index 0000000000..4575e8ef16 Binary files /dev/null and b/solutions/android/VirtualAssistantClient/app/src/main/res/raw/earcon_results.wav differ diff --git a/solutions/android/VirtualAssistantClient/app/src/main/res/values/strings.xml b/solutions/android/VirtualAssistantClient/app/src/main/res/values/strings.xml index bae97cd534..0ffd9cab5b 100644 --- a/solutions/android/VirtualAssistantClient/app/src/main/res/values/strings.xml +++ b/solutions/android/VirtualAssistantClient/app/src/main/res/values/strings.xml @@ -26,6 +26,7 @@ Send Welcome Event Disable Overlay Show Textinput + Show full conversation Inject Adaptive Card Event Reset Bot Enable KWS diff --git a/solutions/android/VirtualAssistantClient/readme.md b/solutions/android/VirtualAssistantClient/readme.md index dfdd07124b..e0d358962e 100644 --- a/solutions/android/VirtualAssistantClient/readme.md +++ b/solutions/android/VirtualAssistantClient/readme.md @@ -1,3 +1,72 @@ # Virtual Assistant Android Client Application -## Coming Soon \ No newline at end of file +## Building the Project + +### Prerequisites + +- [Create a Virtual Assistant](/docs/tutorials/csharp/virtualassistant.md) to setup your environment. + +### Step 1 - Credentials + +Edit `DefaultConfiguration.java` to provide the Speech Cognitive Service key, Speech Channel Secret and UserId which will be used to perform speech operations and identify the user uniquely. Note that there are two versions, one for debug and one for release build flavors. + +The [Speech enabling your Virtual Assistant](https://github.com/microsoft/botframework-solutions/blob/master/docs/howto/assistant/csharp/speechenablement.md) documentation covers the following two steps which you must perform to retrieve the Speech Cognitive Service Key and Speech Channel secret. + +- [Create a Speech Cognitive Service Key](https://github.com/microsoft/botframework-solutions/blob/master/docs/howto/assistant/csharp/speechenablement.md#create-a-microsoft-speech-instance) +- [Add the Speech Channel to your assistant](https://github.com/microsoft/botframework-solutions/blob/master/docs/howto/assistant/csharp/speechenablement.md#add-the-speech-channel-to-your-assistant) + +The UserId is a unique identifier for all messages generated by the user, this is typically combind with [Linked Accounts](https://github.com/microsoft/botframework-solutions/blob/master/docs/howto/assistant/linkedaccounts.md). + +### Step 2 - Deploy +1. Select the desired build flavor (debug or release) +2. Deploy to emulator or device + +## Using the Project +### Running for First Time +- Accept the Record Audio permission to make voice requests from the bot. Without this permission, the user can only type requests to the Bot. +- Accept the Fine Location permission to easily make voice requests that are related to your GPS location, such as "find the nearest coffee shop". Without this permission, the user will be asked by the Bot to provide the current location. +- Slide away the service notification + +### The UI +1. The Mic button is the only graphic immediately visible - press it to make a voice request. (The app will sense when you've finished speaking) + +2. The Navigation Drawer (on the left side of the screen) provides the following functionality: +- Bot Configuration +- App Configuration +- Reset Bot +- Send Location Event +- Send Welcome Event +- Inject Adaptive Card Event +- Show Assistant Settings +- Show Textinput + +### Functionality Overview +#### Bot Configuration +The data on this screen is originally read from "DefaultConfiguration.java". Changing the values on this screen will update the stored data and used immediately. +NOTE: the stored data persists between app installs + +#### App Configuration +Settings that are specific to the app can be set here + +#### Reset Bot +If the bot enters a problematic state, you can reset it. + +#### Send Location Event +Send a location event using the latitude and longitude values found in the "DefaultConfiguration.java" + +#### Send Welcome Event +Triggers the Bot to respond with a default "Welcome" card + +#### Inject Adaptive Card Event +To test rendering of an Adaptive Card. First, create the adaptive card Json at [Adaptive Cards Designer](https://adaptivecards.io/designer/ "Adaptive Cards Designer"). +Second, copy the generated Json into MainActivity.onNavigationItemSelected(). +Finally run the app and "inject" the adaptive card to see what it looks like when sent by the Bot. + +#### Show Assistant Settings +Shortcut to the Android Assistant Settings + +#### Show Textinput +Shows the text input field to make requests without needing to speak + + + diff --git a/templates/Skill-Template/csharp/Sample/SkillSample/Deployment/Scripts/publish.ps1 b/templates/Skill-Template/csharp/Sample/SkillSample/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/templates/Skill-Template/csharp/Sample/SkillSample/Deployment/Scripts/publish.ps1 +++ b/templates/Skill-Template/csharp/Sample/SkillSample/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/templates/Skill-Template/csharp/Template/Skill/Deployment/Scripts/publish.ps1 b/templates/Skill-Template/csharp/Template/Skill/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/templates/Skill-Template/csharp/Template/Skill/Deployment/Scripts/publish.ps1 +++ b/templates/Skill-Template/csharp/Template/Skill/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/csharp/Sample/VirtualAssistantSample/Deployment/Scripts/publish.ps1 b/templates/Virtual-Assistant-Template/csharp/Sample/VirtualAssistantSample/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/templates/Virtual-Assistant-Template/csharp/Sample/VirtualAssistantSample/Deployment/Scripts/publish.ps1 +++ b/templates/Virtual-Assistant-Template/csharp/Sample/VirtualAssistantSample/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/csharp/Template/VA/Deployment/Scripts/publish.ps1 b/templates/Virtual-Assistant-Template/csharp/Template/VA/Deployment/Scripts/publish.ps1 index 87d9dce57d..7fbd70786a 100644 --- a/templates/Virtual-Assistant-Template/csharp/Template/VA/Deployment/Scripts/publish.ps1 +++ b/templates/Virtual-Assistant-Template/csharp/Template/VA/Deployment/Scripts/publish.ps1 @@ -33,12 +33,24 @@ if (Test-Path $zipPath) { Remove-Item $zipPath -Force | Out-Null } -# Compress source code -Get-ChildItem -Path "$($projFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null - -# Publish zip to Azure -Write-Host "> Publishing to Azure ..." -(az webapp deployment source config-zip ` - --resource-group $resourceGroup ` - --name $name ` - --src $zipPath) 2>> $logFile | Out-Null \ No newline at end of file +# Perform dotnet publish step ahead of zipping up +$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2') +dotnet publish -c release -o $publishFolder -v q > $logFile + +if($?) +{ + # Compress source code + Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null + + # Publish zip to Azure + Write-Host "> Publishing to Azure ..." -ForegroundColor Green + (az webapp deployment source config-zip ` + --resource-group $resourceGroup ` + --name $name ` + --src $zipPath) 2>> $logFile | Out-Null +} +else +{ + Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed + Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed +} \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/src/copier.js b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/src/copier.js index 94e5a3d6d6..f1be537e2f 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/src/copier.js +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/src/copier.js @@ -69,6 +69,7 @@ class Copier { // Here you have to add the paths of your templates files loadTemplatesFiles(newAssistant) { templateFiles.set(`_package.json`, `package.json`); + templateFiles.set(`_.eslintrc.js`, `.eslintrc.js`); templateFiles.set(`_.gitignore`, `.gitignore`); templateFiles.set(`_.npmrc`, `.npmrc`); templateFiles.set(`_.nycrc`, `.nycrc`); diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_.eslintrc.js b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_.eslintrc.js new file mode 100644 index 0000000000..e791db9e2a --- /dev/null +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + plugins: [ + '@typescript-eslint', + '@typescript-eslint/tslint' + ], + extends: [ + 'plugin:@typescript-eslint/recommended' + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + project: './tsconfig.json' + }, + rules: { + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + 'args': 'none' + }], + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/interface-name-prefix': [ 'error', 'always' ], + '@typescript-eslint/no-angle-bracket-type-assertion': 'off', + '@typescript-eslint/tslint/config': [ + 'warn', + { + lintFile: './tslint.json' + } + ] + }, +}; \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_package.json b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_package.json index 2f67c9acd7..7f2827a0d9 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_package.json +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/_package.json @@ -10,8 +10,8 @@ "copy-templates": "copyfiles --up 1 \"./src/**/*.json\" \"./lib\"", "prebuild": "npm run lint", "build": "tsc --p tsconfig.json && npm run copy-templates", - "lint": "tslint -t vso ./src/**/*.ts", - "lint-fix": "tslint --fix ./src/**/*.ts", + "lint": "eslint ./src/**/*.ts", + "lint-fix": "eslint --fix ./src/**/*.ts", "start": "npm run build && node ./lib/index.js NODE_ENV=development", "watch": "nodemon ./lib/index.js NODE_ENV=development", "test": "mocha", @@ -39,7 +39,11 @@ "devDependencies": { "@types/i18next-node-fs-backend": "^0.0.30", "@types/restify": "^7.2.4", + "@typescript-eslint/eslint-plugin": "^1.10.2", + "@typescript-eslint/eslint-plugin-tslint": "^1.10.2", + "@typescript-eslint/parser": "^1.10.2", "copyfiles": "^2.1.0", + "eslint": "^5.16.0", "mocha": "^6.1.4", "mocha-junit-reporter": "^1.22.0", "nock": "^10.0.6", @@ -47,7 +51,7 @@ "nyc": "^14.1.1", "rimraf": "^2.6.2", "tslint": "^5.12.1", - "tslint-microsoft-contrib": "6.0.0", + "tslint-microsoft-contrib": "^6.0.0", "typescript": "^3.2.2" }, "env": { diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/adapters/defaultAdapter.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/adapters/defaultAdapter.ts index c584abb8c7..15ae991eb6 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/adapters/defaultAdapter.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/adapters/defaultAdapter.ts @@ -32,7 +32,7 @@ export class DefaultAdapter extends BotFrameworkAdapter { public readonly skills: ISkillManifest[] = []; public readonly userState: UserState; - constructor( + public constructor( settings: Partial, adapterSettings: Partial, telemetryClient: BotTelemetryClient diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/bots/_dialogBot.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/bots/_dialogBot.ts index 20d24988ac..47aa166872 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/bots/_dialogBot.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/bots/_dialogBot.ts @@ -14,8 +14,7 @@ import { Dialog, DialogContext, DialogSet, - DialogState, - DialogTurnResult } from 'botbuilder-dialogs'; + DialogState } from 'botbuilder-dialogs'; export class DialogBot extends ActivityHandler { private readonly telemetryClient: BotTelemetryClient; @@ -23,7 +22,7 @@ export class DialogBot extends ActivityHandler { private readonly rootDialogId: string; private readonly dialogs: DialogSet; - constructor( + public constructor( conversationState: ConversationState, telemetryClient: BotTelemetryClient, dialog: T) { @@ -36,7 +35,7 @@ export class DialogBot extends ActivityHandler { this.onTurn(this.turn.bind(this)); } - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public async turn(turnContext: TurnContext, next: () => Promise): Promise { // Client notifying this bot took to long to respond (timed out) if (turnContext.activity.code === EndOfConversationCodes.BotTimedOut) { @@ -51,7 +50,7 @@ export class DialogBot extends ActivityHandler { const dc: DialogContext = await this.dialogs.createContext(turnContext); if (dc.activeDialog !== undefined) { - const result: DialogTurnResult = await dc.continueDialog(); + await dc.continueDialog(); } else { await dc.beginDialog(this.rootDialogId); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/cancelDialog.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/cancelDialog.ts index 818e39efab..8845533470 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/cancelDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/cancelDialog.ts @@ -22,7 +22,7 @@ export class CancelDialog extends ComponentDialog { private readonly responder: CancelResponses = new CancelResponses(); // Constructor - constructor() { + public constructor() { super(CancelDialog.name); this.initialDialogId = CancelDialog.name; diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/escalateDialog.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/escalateDialog.ts index add07daed6..911047680b 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/escalateDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/escalateDialog.ts @@ -17,7 +17,7 @@ export class EscalateDialog extends ComponentDialog { private readonly responder: EscalateResponses = new EscalateResponses(); // Constructor - constructor(botServices: BotServices, telemetryClient: BotTelemetryClient) { + public constructor(botServices: BotServices, telemetryClient: BotTelemetryClient) { super(EscalateDialog.name); this.initialDialogId = EscalateDialog.name; const escalate: ((sc: WaterfallStepContext) => Promise)[] = [ diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/mainDialog.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/mainDialog.ts index 1d762ac788..906d575625 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/mainDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/mainDialog.ts @@ -47,7 +47,7 @@ export class MainDialog extends RouterDialog { private readonly responder: MainResponses = new MainResponses(); // Constructor - constructor( + public constructor( settings: Partial, services: BotServices, onboardingDialog: OnboardingDialog, @@ -67,7 +67,7 @@ export class MainDialog extends RouterDialog { this.addDialog(escalateDialog); this.addDialog(cancelDialog); - skillDialogs.forEach((skillDialog: SkillDialog) => { + skillDialogs.forEach((skillDialog: SkillDialog): void => { this.addDialog(skillDialog); }); } @@ -228,7 +228,7 @@ export class MainDialog extends RouterDialog { const intent: string = LuisRecognizer.topIntent(luisResult); // Only triggers interruption if confidence level is high - if (luisResult.intents[intent] && luisResult.intents[intent].score > 0.5) { + if (luisResult.intents[intent] !== undefined && luisResult.intents[intent].score > 0.5) { switch (intent) { case 'Cancel': { return this.onCancel(dc); @@ -284,7 +284,7 @@ export class MainDialog extends RouterDialog { // Sign out user // PENDING check adapter.getTokenStatusAsync const tokens: TokenStatus[] = []; - tokens.forEach(async (token: TokenStatus) => { + tokens.forEach(async (token: TokenStatus): Promise => { if (token.connectionName !== undefined) { await adapter.signOutUser(dc.context, token.connectionName); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/onboardingDialog.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/onboardingDialog.ts index 0bab821fe0..a943101e93 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/onboardingDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/dialogs/onboardingDialog.ts @@ -30,7 +30,7 @@ export class OnboardingDialog extends ComponentDialog { private state!: IOnboardingState; // Constructor - constructor(botServices: BotServices, accessor: StatePropertyAccessor, telemetryClient: BotTelemetryClient) { + public constructor(botServices: BotServices, accessor: StatePropertyAccessor, telemetryClient: BotTelemetryClient) { super(OnboardingDialog.name); this.accessor = accessor; this.initialDialogId = OnboardingDialog.name; @@ -91,4 +91,4 @@ export class OnboardingDialog extends ComponentDialog { return state; } - } +} diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/index.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/index.ts index 8ac8f0ea6d..8dfc51fa2d 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/index.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/index.ts @@ -18,6 +18,7 @@ import { Locales, MultiProviderAuthDialog } from 'botbuilder-solutions'; import i18next from 'i18next'; +// tslint:disable-next-line: match-default-export-name import i18nextNodeFsBackend from 'i18next-node-fs-backend'; import * as path from 'path'; import * as restify from 'restify'; @@ -35,23 +36,24 @@ import { IBotSettings } from './services/botSettings'; import { skills as skillsRaw } from './skills.json'; // Configure internationalization and default locale +// tslint:disable-next-line: no-floating-promises i18next.use(i18nextNodeFsBackend) -.init({ - fallbackLng: 'en', - preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ], - backend: { - loadPath: path.join(__dirname, 'locales', '{{lng}}.json') - } -}) -.then(async () => { - await Locales.addResourcesFromPath(i18next, 'common'); -}); + .init({ + fallbackLng: 'en', + preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ], + backend: { + loadPath: path.join(__dirname, 'locales', '{{lng}}.json') + } + }) + .then(async (): Promise => { + await Locales.addResourcesFromPath(i18next, 'common'); + }); const skills: ISkillManifest[] = skillsRaw; const cognitiveModels: Map = new Map(); const cognitiveModelDictionary: { [key: string]: Object } = cognitiveModelsRaw.cognitiveModels; const cognitiveModelMap: Map = new Map(Object.entries(cognitiveModelDictionary)); -cognitiveModelMap.forEach((value: Object, key: string) => { +cognitiveModelMap.forEach((value: Object, key: string): void => { cognitiveModels.set(key, value); }); @@ -67,7 +69,7 @@ const botSettings: Partial = { }; function getTelemetryClient(settings: Partial): BotTelemetryClient { - if (settings && settings.appInsights && settings.appInsights.instrumentationKey) { + if (settings !== undefined && settings.appInsights !== undefined && settings.appInsights.instrumentationKey !== undefined) { const instrumentationKey: string = settings.appInsights.instrumentationKey; return new ApplicationInsightsTelemetryClient(instrumentationKey); @@ -96,7 +98,7 @@ try { const onboardingDialog: OnboardingDialog = new OnboardingDialog(botServices, onboardingStateAccessor, telemetryClient); const escalateDialog: EscalateDialog = new EscalateDialog(botServices, telemetryClient); const cancelDialog: CancelDialog = new CancelDialog(); - const skillDialogs: SkillDialog[] = skills.map((skill: ISkillManifest) => { + const skillDialogs: SkillDialog[] = skills.map((skill: ISkillManifest): SkillDialog => { const authDialog: MultiProviderAuthDialog|undefined = buildAuthDialog(skill, botSettings); const credentials: MicrosoftAppCredentialsEx = new MicrosoftAppCredentialsEx( botSettings.microsoftAppId || '', @@ -127,6 +129,7 @@ const server: restify.Server = restify.createServer(); // Enable the Application Insights middleware, which helps correlate all activity // based on the incoming request. server.use(restify.plugins.bodyParser()); +// tslint:disable-next-line:no-unsafe-any server.use(ApplicationInsightsWebserverMiddleware); server.listen(process.env.port || process.env.PORT || '3979', (): void => { @@ -139,9 +142,9 @@ server.listen(process.env.port || process.env.PORT || '3979', (): void => { }); // Listen for incoming requests -server.post('/api/messages', (req: restify.Request, res: restify.Response) => { +server.post('/api/messages', async (req: restify.Request, res: restify.Response): Promise => { // Route received a request to adapter for processing - adapter.processActivity(req, res, async (turnContext: TurnContext) => { + await adapter.processActivity(req, res, async (turnContext: TurnContext): Promise => { // route to bot activity handler. await bot.run(turnContext); }); @@ -152,11 +155,11 @@ function buildAuthDialog(skill: ISkillManifest, settings: Partial) if (skill.authenticationConnections !== undefined && skill.authenticationConnections.length > 0) { if (settings.oauthConnections !== undefined) { const oauthConnections: IOAuthConnection[] | undefined = settings.oauthConnections.filter( - (oauthConnection: IOAuthConnection) => { - return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection) => { - return authenticationConnection.serviceProviderId === oauthConnection.provider; + (oauthConnection: IOAuthConnection): boolean => { + return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection): boolean => { + return authenticationConnection.serviceProviderId === oauthConnection.provider; + }); }); - }); if (oauthConnections !== undefined) { return new MultiProviderAuthDialog(oauthConnections); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/cancelResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/cancelResponses.ts index 1be49baa67..dd95764878 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/cancelResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/cancelResponses.ts @@ -36,7 +36,7 @@ export class CancelResponses extends TemplateManager { ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(CancelResponses.responseTemplates)); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/escalateResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/escalateResponses.ts index 4b52a6a6d3..d2be3f7e7e 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/escalateResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/escalateResponses.ts @@ -20,7 +20,7 @@ export class EscalateResponses extends TemplateManager { // Declare here the type of properties and the prompts public static responseIds: { - sendPhoneMessage : string; + sendPhoneMessage: string; } = { sendPhoneMessage: 'sendPhoneMessage' }; @@ -28,19 +28,21 @@ export class EscalateResponses extends TemplateManager { // Declare the responses map prompts private static readonly responseTemplates: LanguageTemplateDictionary = new Map([ ['default', new Map([ - [EscalateResponses.responseIds.sendPhoneMessage, - // tslint:disable-next-line: no-any - (context: TurnContext, data: any): Promise => EscalateResponses.buildEscalateCard(context, data)] + [ + EscalateResponses.responseIds.sendPhoneMessage, + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + (context: TurnContext, data: any): Promise => EscalateResponses.buildEscalateCard(context, data) + ] ])] ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(EscalateResponses.responseTemplates)); } - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildEscalateCard(turnContext: TurnContext, data: any): Promise { const response: Activity = ActivityExtensions.createReply(turnContext.activity); diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/mainResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/mainResponses.ts index b756ef9f61..8d8bda4a8c 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/mainResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/mainResponses.ts @@ -11,6 +11,7 @@ import { MessageFactory, TurnContext } from 'botbuilder'; import { ActionTypes } from 'botframework-schema'; +import { readFileSync } from 'fs'; import i18next from 'i18next'; import { join } from 'path'; import { @@ -54,18 +55,19 @@ export class MainResponses extends TemplateManager { ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(MainResponses.responseTemplates)); } - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildNewUserGreetingCard(turnContext: TurnContext, data: any): Promise { const introFileName: string = i18next.t('main.introGreetingFile'); const introPath: string = join(__dirname, '..', 'content', introFileName); - // tslint:disable-next-line:no-any non-literal-require - const introCard: any = require(introPath); + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + const introCard: any = JSON.parse(readFileSync(introPath, 'UTF8')); const attachment: Attachment = CardFactory.adaptiveCard(introCard); + // eslint-disable-next-line @typescript-eslint/tslint/config const response: Partial = MessageFactory.attachment(attachment, '', attachment.content.speak, InputHints.AcceptingInput); response.suggestedActions = { @@ -92,13 +94,14 @@ export class MainResponses extends TemplateManager { return Promise.resolve(response); } - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildReturningUserGreetingCard(turnContext: TurnContext, data: any): Promise { const introFileName: string = i18next.t('main.introReturningFile'); const introPath: string = join(__dirname, '..', 'content', introFileName); - // tslint:disable-next-line:no-any non-literal-require - const introCard: any = require(introPath); + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + const introCard: any = JSON.parse(readFileSync(introPath, 'UTF8')); const attachment: Attachment = CardFactory.adaptiveCard(introCard); + // eslint-disable-next-line @typescript-eslint/tslint/config const response: Partial = MessageFactory.attachment(attachment, '', attachment.content.speak, InputHints.AcceptingInput); response.suggestedActions = { @@ -125,7 +128,7 @@ export class MainResponses extends TemplateManager { return Promise.resolve(response); } - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildHelpCard(turnContext: TurnContext, data: any): Promise { const title: string = i18next.t('main.helpTitle'); const text: string = i18next.t('main.helpText'); @@ -134,21 +137,21 @@ export class MainResponses extends TemplateManager { response.suggestedActions = { actions: [ - { - title: i18next.t('main.helpBtnText1'), - type: ActionTypes.ImBack, - value: i18next.t('main.helpBtnValue1') - }, - { - title: i18next.t('main.helpBtnText2'), - type: ActionTypes.ImBack, - value: i18next.t('main.helpBtnValue2') - }, - { - title: i18next.t('main.helpBtnText3'), - type: ActionTypes.OpenUrl, - value: i18next.t('main.helpBtnValue3') - } + { + title: i18next.t('main.helpBtnText1'), + type: ActionTypes.ImBack, + value: i18next.t('main.helpBtnValue1') + }, + { + title: i18next.t('main.helpBtnText2'), + type: ActionTypes.ImBack, + value: i18next.t('main.helpBtnValue2') + }, + { + title: i18next.t('main.helpBtnText3'), + type: ActionTypes.OpenUrl, + value: i18next.t('main.helpBtnValue3') + } ], to: [] }; diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/onboardingResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/onboardingResponses.ts index 828a0b630b..3603ef0220 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/onboardingResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/responses/onboardingResponses.ts @@ -15,9 +15,9 @@ export class OnboardingResponses extends TemplateManager { // Declare here the type of properties and the prompts public static responseIds: { - emailPrompt : string; - haveEmailMessage : string; - haveNameMessage : string; + emailPrompt: string; + haveEmailMessage: string; + haveNameMessage: string; haveLocationMessage: string; locationPrompt: string; namePrompt: string; @@ -34,23 +34,23 @@ export class OnboardingResponses extends TemplateManager { private static readonly responseTemplates: LanguageTemplateDictionary = new Map([ ['default', new Map([ [OnboardingResponses.responseIds.emailPrompt, OnboardingResponses.fromResources('onboarding.emailPrompt')], - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config [OnboardingResponses.responseIds.haveEmailMessage, async (context: TurnContext, data: any): Promise => { const value: string = i18next.t('onboarding.haveEmail'); // tslint:disable-next-line: no-unsafe-any return value.replace('{0}', data.email); }], - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config [OnboardingResponses.responseIds.haveLocationMessage, async (context: TurnContext, data: any): Promise => { const value: string = i18next.t('onboarding.haveLocation'); // tslint:disable-next-line: no-unsafe-any return value.replace('{0}', data.name) - // tslint:disable-next-line: no-unsafe-any - .replace('{1}', data.location); + // tslint:disable-next-line: no-unsafe-any + .replace('{1}', data.location); }], - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config [OnboardingResponses.responseIds.haveNameMessage, async (context: TurnContext, data: any): Promise => { const value: string = i18next.t('onboarding.haveName'); @@ -63,7 +63,7 @@ export class OnboardingResponses extends TemplateManager { ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(OnboardingResponses.responseTemplates)); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/services/botServices.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/services/botServices.ts index 8d137c2f46..966760dc33 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/services/botServices.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/services/botServices.ts @@ -13,14 +13,14 @@ export class BotServices { public cognitiveModelSets: Map = new Map(); - constructor(settings: Partial, telemetryClient: BotTelemetryClient) { + public constructor(settings: Partial, telemetryClient: BotTelemetryClient) { const luisPredictionOptions: LuisPredictionOptions = { telemetryClient: telemetryClient, logPersonalInformation: true }; if (settings.cognitiveModels !== undefined) { - settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string) => { + settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string): void => { const language: string = key; const config: ICognitiveModelConfiguration = value; @@ -39,7 +39,7 @@ export class BotServices { }; if (config.languageModels !== undefined) { - config.languageModels.forEach((model: LuisService) => { + config.languageModels.forEach((model: LuisService): void => { const luisService: LuisService = new LuisService(model); const luisApp: LuisApplication = { applicationId: luisService.appId, @@ -50,7 +50,7 @@ export class BotServices { }); } - config.knowledgeBases.forEach((kb: QnaMakerService) => { + config.knowledgeBases.forEach((kb: QnaMakerService): void => { const qnaEndpoint: QnAMakerEndpoint = { knowledgeBaseId: kb.kbId, endpointKey: kb.endpointKey, diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/dictionaryRenderer.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/dictionaryRenderer.ts index d7ec2aab01..a04f77d6a5 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/dictionaryRenderer.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/dictionaryRenderer.ts @@ -6,7 +6,7 @@ import { TurnContext } from 'botbuilder-core'; import { ITemplateRenderer } from './templateRenderer'; -// tslint:disable-next-line:no-any +// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config export declare type TemplateFunction = (turnContext: TurnContext, data: any) => Promise; /** @@ -34,17 +34,17 @@ export declare type LanguageTemplateDictionary = Map { const templates: TemplateIdMap | undefined = this.languages.get(language); if (templates !== undefined) { const template: TemplateFunction | undefined = templates.get(templateId); if (template !== undefined) { - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const result: Promise = template(turnContext, data); if (result !== undefined) { return result; diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/graphClient.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/graphClient.ts index e57565df3b..2332a78adf 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/graphClient.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/graphClient.ts @@ -12,21 +12,25 @@ import { User } from '@microsoft/microsoft-graph-types'; export class GraphClient { private readonly token: string; - constructor(token: string) { + public constructor(token: string) { this.token = token; } - public getMe(): Promise { - // tslint:disable-next-line:no-any - return new Promise((resolve: (value?: User | PromiseLike | undefined) => any, reject: (reason?: any) => void): void => { + public async getMe(): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + return new Promise((resolve, reject): Promise => { const client: Client = this.getAuthenticatedClient(); - client.api('/me') - .select('displayName') - .get((err: GraphError, res: User) => { - if (err) { return reject(err); } - return resolve(res); - }); + return client + .api('/me') + .select('displayName') + .get((err: GraphError, res: User): void => { + if (err !== undefined) { + reject(err); + } + + resolve(res); + }); }); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateManager.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateManager.ts index 16e642357d..a76541809b 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateManager.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateManager.ts @@ -17,7 +17,7 @@ export class TemplateManager { * Add a template engine for binding templates */ public register(renderer: ITemplateRenderer): TemplateManager { - if (!this.templateRenders.some((x: ITemplateRenderer) => x === renderer)) { + if (!this.templateRenders.some((x: ITemplateRenderer): boolean => x === renderer)) { this.templateRenders.push(renderer); } @@ -42,7 +42,7 @@ export class TemplateManager { /** * Send a reply with the template */ - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public async replyWith(turnContext: TurnContext, templateId: string, data?: any): Promise { if (turnContext === undefined) { throw new Error('turnContext is null'); } @@ -57,10 +57,13 @@ export class TemplateManager { return; } - public async renderTemplate(turnContext: TurnContext, - templateId: string, - // tslint:disable-next-line:no-any - language?: string, data?: any): Promise { + public async renderTemplate( + turnContext: TurnContext, + templateId: string, + language?: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + data?: any + ): Promise { const fallbackLocales: string[] = this.languageFallback; if (language !== undefined) { @@ -72,11 +75,11 @@ export class TemplateManager { // try each locale until successful for (const locale of fallbackLocales) { for (const renderer of this.templateRenders) { - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const templateOutput: any = await renderer.renderTemplate(turnContext, locale, templateId, data); if (templateOutput) { if (typeof templateOutput === 'string' || templateOutput instanceof String) { - const def : Partial = { type: ActivityTypes.Message, text: templateOutput}; + const def: Partial = { type: ActivityTypes.Message, text: templateOutput}; return def; } else { diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateRenderer.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateRenderer.ts index 3ea1cda8c0..d7a975060d 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateRenderer.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/src/templateManager/templateRenderer.ts @@ -17,6 +17,6 @@ export interface ITemplateRenderer { * @param templateId - template to render * @param data - data object to use to render */ - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config renderTemplate(turnContext: TurnContext, language: string, templateId: string, data: any): Promise; } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/tslint.json b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/tslint.json index 46630b8017..91c8a37d7d 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/tslint.json +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/app/templates/sample-assistant/tslint.json @@ -17,20 +17,26 @@ "static-method-regex": "^[a-z][\\w\\d]+$" } ], - "linebreak-style": [ - false - ], - "member-ordering": [ - false - ], - "no-relative-imports": [ - false + "strict-boolean-expressions": [ + true, + "allow-undefined-union", + "allow-null-union", + "allow-mix", + "allow-string", + "ignore-rhs" ], - "completed-docs": [ - false - ] + "linebreak-style": false, + "completed-docs": false, + "no-relative-imports": false, + "export-name": false, + "member-ordering": false, + "no-use-before-declare": false, + "no-function-constructor-with-string-args": false, + "no-reserved-keywords": false, + "no-increment-decrement": false, + "no-unnecessary-bind": false }, "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" + "tslint-microsoft-contrib" ] } \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/src/copier.js b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/src/copier.js index 50f49bab11..8af046c5ae 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/src/copier.js +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/src/copier.js @@ -63,6 +63,7 @@ class Copier { // Here you have to add the paths of your templates files loadTemplatesFiles(newSkill) { templateFiles.set(`_package.json`, `package.json`); + templateFiles.set(`_.eslintrc.js`, `.eslintrc.js`); templateFiles.set(`_.gitignore`, `.gitignore`); templateFiles.set(`_.npmrc`, `.npmrc`); templateFiles.set(`_.nycrc`, `.nycrc`); diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/customSkill/test/mocks/nockFixtures/mainDialog_intro_response.json b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/customSkill/test/mocks/nockFixtures/mainDialog_intro_response.json deleted file mode 100644 index 0637a088a0..0000000000 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/customSkill/test/mocks/nockFixtures/mainDialog_intro_response.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_.eslintrc.js b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_.eslintrc.js new file mode 100644 index 0000000000..e791db9e2a --- /dev/null +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + plugins: [ + '@typescript-eslint', + '@typescript-eslint/tslint' + ], + extends: [ + 'plugin:@typescript-eslint/recommended' + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + project: './tsconfig.json' + }, + rules: { + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + 'args': 'none' + }], + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/interface-name-prefix': [ 'error', 'always' ], + '@typescript-eslint/no-angle-bracket-type-assertion': 'off', + '@typescript-eslint/tslint/config': [ + 'warn', + { + lintFile: './tslint.json' + } + ] + }, +}; \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_package.json b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_package.json index e0b7247771..65fa359e91 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_package.json +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/_package.json @@ -10,8 +10,8 @@ "copy-templates": "copyfiles --up 1 \"./src/**/*.json\" \"./lib\"", "prebuild": "npm run lint", "build": "tsc --p tsconfig.json && npm run copy-templates", - "lint": "tslint -t vso ./src/**/*.ts", - "lint-fix": "tslint --fix ./src/**/*.ts", + "lint": "eslint ./src/**/*.ts", + "lint-fix": "eslint --fix ./src/**/*.ts", "start": "npm run build && node ./lib/index.js NODE_ENV=development", "watch": "nodemon ./lib/index.js NODE_ENV=development", "test": "mocha", @@ -38,7 +38,11 @@ "@types/i18next-node-fs-backend": "^0.0.30", "@types/node": "^10.10.1", "@types/restify": "^7.2.4", + "@typescript-eslint/eslint-plugin": "^1.10.2", + "@typescript-eslint/eslint-plugin-tslint": "^1.10.2", + "@typescript-eslint/parser": "^1.10.2", "copyfiles": "^2.1.0", + "eslint": "^5.16.0", "nock": "^10.0.6", "mocha": "^6.1.4", "mocha-junit-reporter": "^1.22.0", @@ -47,7 +51,7 @@ "replace": "^1.0.0", "rimraf": "^2.6.2", "tslint": "^5.12.1", - "tslint-microsoft-contrib": "6.0.0", + "tslint-microsoft-contrib": "^6.0.0", "typescript": "^3.2.2" }, "env": { diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/defaultAdapter.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/defaultAdapter.ts index fca85dbecb..0acd44eaee 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/defaultAdapter.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/defaultAdapter.ts @@ -21,7 +21,7 @@ import { import { IBotSettings } from '../services/botSettings'; export class DefaultAdapter extends BotFrameworkAdapter { - constructor( + public constructor( settings: Partial, adapterSettings: Partial, userState: UserState, diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/sampleSkillAdapter.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/sampleSkillAdapter.ts index e27a06404b..ef5a135dd5 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/sampleSkillAdapter.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/adapters/sampleSkillAdapter.ts @@ -24,7 +24,7 @@ import { IBotSettings } from '../services/botSettings'; export class SampleSkillAdapter extends SkillHttpBotAdapter { - constructor( + public constructor( settings: Partial, userState: UserState, conversationState: ConversationState, diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/bots/_dialogBot.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/bots/_dialogBot.ts index bdd8cb8898..c989156987 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/bots/_dialogBot.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/bots/_dialogBot.ts @@ -14,19 +14,19 @@ import { Dialog, DialogContext, DialogSet, - DialogState, - DialogTurnResult } from 'botbuilder-dialogs'; + DialogState } from 'botbuilder-dialogs'; export class DialogBot extends ActivityHandler { private readonly telemetryClient: BotTelemetryClient; private readonly solutionName: string = '<%=skillNameCamelCase%>'; private readonly rootDialogId: string; - private dialogs: DialogSet; + private readonly dialogs: DialogSet; - constructor( + public constructor( conversationState: ConversationState, telemetryClient: BotTelemetryClient, - dialog: T) { + dialog: T + ) { super(); this.rootDialogId = dialog.id; @@ -36,7 +36,7 @@ export class DialogBot extends ActivityHandler { this.onTurn(this.turn.bind(this)); } - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public async turn(turnContext: TurnContext, next: () => Promise): Promise { // Client notifying this bot took to long to respond (timed out) if (turnContext.activity.code === EndOfConversationCodes.BotTimedOut) { @@ -51,7 +51,7 @@ export class DialogBot extends ActivityHandler { const dc: DialogContext = await this.dialogs.createContext(turnContext); if (dc.activeDialog !== undefined) { - const result: DialogTurnResult = await dc.continueDialog(); + await dc.continueDialog(); } else { await dc.beginDialog(this.rootDialogId); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_mainDialog.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_mainDialog.ts index a0a5c2bd48..943a66852d 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_mainDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_mainDialog.ts @@ -50,7 +50,7 @@ export class MainDialog extends RouterDialog { private readonly contextAccessor: StatePropertyAccessor; // Constructor - constructor( + public constructor( settings: Partial, services: BotServices, responseManager: ResponseManager, @@ -74,7 +74,6 @@ export class MainDialog extends RouterDialog { } protected async onStart(dc: DialogContext): Promise { - const locale: string = i18next.language; await dc.context.sendActivity(this.responseManager.getResponse(MainResponses.welcomeMessage)); } @@ -138,8 +137,6 @@ export class MainDialog extends RouterDialog { protected async onEvent(dc: DialogContext): Promise { switch (dc.context.activity.name) { case Events.skillBeginEvent: { - // tslint:disable-next-line: no-any - const state: any = await this.stateAccessor.get(dc.context); const userData: Map = >dc.context.activity.value; if (userData === undefined) { throw new Error('userData is not an instance of Map'); @@ -236,7 +233,7 @@ export class MainDialog extends RouterDialog { // Sign out user // PENDING check adapter.getTokenStatusAsync const tokens: TokenStatus[] = []; - tokens.forEach(async (token: TokenStatus) => { + tokens.forEach(async (token: TokenStatus): Promise => { if (token.connectionName !== undefined) { await adapter.signOutUser(dc.context, token.connectionName); } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_skillDialogBase.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_skillDialogBase.ts index 0acf62d7df..8703a3e37e 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_skillDialogBase.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/_skillDialogBase.ts @@ -30,10 +30,6 @@ import { SharedResponses } from '../responses/shared/sharedResponses'; import { BotServices} from '../services/botServices'; import { IBotSettings } from '../services/botSettings'; -enum DialogIds { - skillModeAuth = 'SkillAuth' -} - export class SkillDialogBase extends ComponentDialog { private readonly solutionName: string = '<%=skillNameCamelCase%>'; protected settings: Partial; @@ -41,13 +37,14 @@ export class SkillDialogBase extends ComponentDialog { protected stateAccessor: StatePropertyAccessor; protected responseManager: ResponseManager; - constructor( + public constructor( dialogId: string, settings: Partial, services: BotServices, responseManager: ResponseManager, stateAccessor: StatePropertyAccessor, - telemetryClient: BotTelemetryClient) { + telemetryClient: BotTelemetryClient + ) { super(dialogId); this.services = services; this.responseManager = responseManager; @@ -97,9 +94,9 @@ export class SkillDialogBase extends ComponentDialog { const providerTokenResponse: IProviderTokenResponse | undefined = sc.result; if (providerTokenResponse !== undefined) { - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const state: any = await this.stateAccessor.get(sc.context); - // tslint:disable-next-line: no-unsafe-any + // tslint:disable-next-line: no-any no-unsafe-any state.token = providerTokenResponse.tokenResponse.token; } @@ -175,7 +172,7 @@ export class SkillDialogBase extends ComponentDialog { await sc.context.sendActivity(this.responseManager.getResponse(SharedResponses.errorMessage)); // clear state - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const state: any = await this.stateAccessor.get(sc.context); // tslint:disable-next-line: no-unsafe-any state.clear(); diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/sampleDialog.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/sampleDialog.ts index aa69a965c5..8a5923cfce 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/sampleDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/dialogs/sampleDialog.ts @@ -27,7 +27,7 @@ export class SampleDialog extends SkillDialogBase { private readonly nameKey: string = 'name'; // Constructor - constructor( + public constructor( settings: Partial, services: BotServices, responseManager: ResponseManager, @@ -66,7 +66,7 @@ export class SampleDialog extends SkillDialogBase { const tokens: Map = new Map(); tokens.set(this.nameKey, sc.result); - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const response: any = this.responseManager.getResponse(SampleResponses.haveNameMessage, tokens); // tslint:disable-next-line: no-unsafe-any await sc.context.sendActivity(response); diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/index.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/index.ts index 9e515545d0..d726543182 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/index.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/index.ts @@ -19,18 +19,15 @@ import { Dialog, DialogState } from 'botbuilder-dialogs'; import { - IAuthenticationConnection, - ISkillManifest, manifestGenerator, SkillContext, SkillHttpAdapter } from 'botbuilder-skills'; import { ICognitiveModelConfiguration, - IOAuthConnection, Locales, - MultiProviderAuthDialog, ResponseManager} from 'botbuilder-solutions'; import i18next from 'i18next'; +// tslint:disable-next-line: match-default-export-name import i18nextNodeFsBackend from 'i18next-node-fs-backend'; import { join } from 'path'; import * as restify from 'restify'; @@ -49,19 +46,20 @@ import { BotServices } from './services/botServices'; import { IBotSettings } from './services/botSettings'; // Configure internationalization and default locale +// tslint:disable-next-line: no-floating-promises i18next.use(i18nextNodeFsBackend) -.init({ - fallbackLng: 'en', - preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ] -}) -.then(async () => { - await Locales.addResourcesFromPath(i18next, 'common'); -}); + .init({ + fallbackLng: 'en', + preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ] + }) + .then(async (): Promise => { + await Locales.addResourcesFromPath(i18next, 'common'); + }); const cognitiveModels: Map = new Map(); const cognitiveModelDictionary: { [key: string]: Object } = cognitiveModelsRaw.cognitiveModels; const cognitiveModelMap: Map = new Map(Object.entries(cognitiveModelDictionary)); -cognitiveModelMap.forEach((value: Object, key: string) => { +cognitiveModelMap.forEach((value: Object, key: string): void => { cognitiveModels.set(key, value); }); @@ -79,7 +77,7 @@ if (botSettings.appInsights === undefined) { } function getTelemetryClient(settings: Partial): BotTelemetryClient { - if (settings && settings.appInsights && settings.appInsights.instrumentationKey) { + if (settings !== undefined && settings.appInsights !== undefined && settings.appInsights.instrumentationKey !== undefined) { const instrumentationKey: string = settings.appInsights.instrumentationKey; return new ApplicationInsightsTelemetryClient(instrumentationKey); @@ -166,6 +164,7 @@ const server: restify.Server = restify.createServer(); // Enable the Application Insights middleware, which helps correlate all activity // based on the incoming request. server.use(restify.plugins.bodyParser()); +// tslint:disable-next-line:no-unsafe-any server.use(ApplicationInsightsWebserverMiddleware); server.listen(process.env.port || process.env.PORT || '3980', (): void => { @@ -178,18 +177,18 @@ server.listen(process.env.port || process.env.PORT || '3980', (): void => { }); // Listen for incoming requests -server.post('/api/messages', (req: restify.Request, res: restify.Response) => { +server.post('/api/messages', async (req: restify.Request, res: restify.Response): Promise => { // Route received a request to adapter for processing - botAdapter.processActivity(req, res, async (turnContext: TurnContext) => { + await botAdapter.processActivity(req, res, async (turnContext: TurnContext): Promise => { // route to bot activity handler. await bot.run(turnContext); }); }); // Listen for incoming assistant requests -server.post('/api/skill/messages', (req: restify.Request, res: restify.Response) => { +server.post('/api/skill/messages', async (req: restify.Request, res: restify.Response): Promise => { // Route received a request to adapter for processing - adapter.processActivity(req, res, async (turnContext: TurnContext) => { + await adapter.processActivity(req, res, async (turnContext: TurnContext): Promise => { // route to bot activity handler. await bot.run(turnContext); }); @@ -198,24 +197,3 @@ server.post('/api/skill/messages', (req: restify.Request, res: restify.Response) const manifestPath: string = join(__dirname, 'manifestTemplate.json'); server.use(restify.plugins.queryParser()); server.get('/api/skill/manifest', manifestGenerator(manifestPath, botSettings)); - -// This method creates a MultiProviderAuthDialog based on a skill manifest. -function buildAuthDialog(skill: ISkillManifest, settings: Partial): MultiProviderAuthDialog|undefined { - if (skill.authenticationConnections !== undefined && skill.authenticationConnections.length > 0) { - if (settings.oauthConnections !== undefined) { - const oauthConnections: IOAuthConnection[] | undefined = settings.oauthConnections.filter( - (oauthConnection: IOAuthConnection) => { - return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection) => { - return authenticationConnection.serviceProviderId === oauthConnection.provider; - }); - }); - if (oauthConnections !== undefined) { - return new MultiProviderAuthDialog(oauthConnections); - } - } else { - throw new Error(`You must configure at least one supported OAuth connection to use this skill: ${skill.name}.`); - } - } - - return undefined; -} diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/main/mainResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/main/mainResponses.ts index 0170823dfa..85cf31432a 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/main/mainResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/main/mainResponses.ts @@ -15,9 +15,9 @@ export class MainResponses implements IResponseIdCollection { public static pathToResource?: string = join(__dirname, 'resources'); public static readonly welcomeMessage: string = 'WelcomeMessage'; public static readonly helpMessage: string = 'HelpMessage'; - public static readonly greetingMessage : string = 'GreetingMessage'; - public static readonly goodbyeMessage : string = 'GoodbyeMessage'; - public static readonly logOut : string = 'LogOut'; - public static readonly featureNotAvailable : string = 'FeatureNotAvailable'; + public static readonly greetingMessage: string = 'GreetingMessage'; + public static readonly goodbyeMessage: string = 'GoodbyeMessage'; + public static readonly logOut: string = 'LogOut'; + public static readonly featureNotAvailable: string = 'FeatureNotAvailable'; public static readonly cancelMessage: string = 'CancelMessage'; } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/sample/sampleResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/sample/sampleResponses.ts index 8cf8a3a179..9fcb699222 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/sample/sampleResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/sample/sampleResponses.ts @@ -13,6 +13,6 @@ export class SampleResponses implements IResponseIdCollection { // Generated accessors public name: string = SampleResponses.name; public static pathToResource?: string = join(__dirname, 'resources'); - public static readonly namePrompt : string = 'NamePrompt'; - public static readonly haveNameMessage : string = 'HaveNameMessage'; + public static readonly namePrompt: string = 'NamePrompt'; + public static readonly haveNameMessage: string = 'HaveNameMessage'; } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/shared/sharedResponses.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/shared/sharedResponses.ts index 3c2732a0d2..38dcc00b50 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/shared/sharedResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/responses/shared/sharedResponses.ts @@ -13,10 +13,10 @@ export class SharedResponses implements IResponseIdCollection { // Generated accessors public name: string = SharedResponses.name; public static pathToResource?: string = join(__dirname, 'resources'); - public static readonly didntUnderstandMessage : string = 'DidntUnderstandMessage'; - public static readonly cancellingMessage : string = 'CancellingMessage'; - public static readonly noAuth : string = 'NoAuth'; - public static readonly authFailed : string = 'AuthFailed'; - public static readonly actionEnded : string = 'ActionEnded'; - public static readonly errorMessage : string = 'ErrorMessage'; + public static readonly didntUnderstandMessage: string = 'DidntUnderstandMessage'; + public static readonly cancellingMessage: string = 'CancellingMessage'; + public static readonly noAuth: string = 'NoAuth'; + public static readonly authFailed: string = 'AuthFailed'; + public static readonly actionEnded: string = 'ActionEnded'; + public static readonly errorMessage: string = 'ErrorMessage'; } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botServices.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botServices.ts index e3aa65e756..368e6c301e 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botServices.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botServices.ts @@ -15,7 +15,7 @@ export class BotServices { public cognitiveModelSets: Map> = new Map(); - constructor(settings: Partial, telemetryClient: BotTelemetryClient) { + public constructor(settings: Partial, telemetryClient: BotTelemetryClient) { const luisPredictionOptions: LuisPredictionOptions = { telemetryClient: telemetryClient, logPersonalInformation: true @@ -24,14 +24,14 @@ export class BotServices { try { if (settings.cognitiveModels !== undefined) { - settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string) => { + settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string): void => { const language: string = key; const config: ICognitiveModelConfiguration = value; const cognitiveModelSet: Partial = { luisServices: new Map() }; - config.languageModels.forEach((model: LuisService) => { + config.languageModels.forEach((model: LuisService): void => { const luisService: LuisService = new LuisService(model); const luisApp: LuisApplication = { applicationId: luisService.appId, @@ -47,7 +47,7 @@ export class BotServices { }); } } catch (err) { - throw new Error(err); + throw err; } } } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botSettings.ts b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botSettings.ts index 5f951f6bf7..8068cbe30a 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botSettings.ts +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/src/services/botSettings.ts @@ -4,7 +4,7 @@ */ import { IBotSettingsBase } from 'botbuilder-solutions'; -// tslint:disable-next-line: no-empty-interface +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/tslint/config export interface IBotSettings extends IBotSettingsBase { } diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/tslint.json b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/tslint.json index a177ef07ec..91c8a37d7d 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/tslint.json +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/generators/skill/templates/sample-skill/tslint.json @@ -1,26 +1,42 @@ { - "defaultSeverity": "error", - "extends": [ - "tslint:recommended", - "tslint-microsoft-contrib" - ], - "linterOptions":{ - "exclude": [ - "src/dialogs/shared/resources/*" - ] - }, - "rules": { - "function-name": [ true, - { - "static-method-regex":"^[a-z][\\w\\d]+$" - } - ], - "linebreak-style": [false], - "member-ordering": [false], - "no-relative-imports": [false], - "completed-docs": [false] - }, - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" + "defaultSeverity": "error", + "extends": [ + "tslint:recommended", + "tslint-microsoft-contrib" + ], + "linterOptions": { + "exclude": [ + "src/dialogs/shared/resources/*", + "src/services/DispatchLuis.ts" ] - } \ No newline at end of file + }, + "rules": { + "function-name": [ + true, + { + "static-method-regex": "^[a-z][\\w\\d]+$" + } + ], + "strict-boolean-expressions": [ + true, + "allow-undefined-union", + "allow-null-union", + "allow-mix", + "allow-string", + "ignore-rhs" + ], + "linebreak-style": false, + "completed-docs": false, + "no-relative-imports": false, + "export-name": false, + "member-ordering": false, + "no-use-before-declare": false, + "no-function-constructor-with-string-args": false, + "no-reserved-keywords": false, + "no-increment-decrement": false, + "no-unnecessary-bind": false + }, + "rulesDirectory": [ + "tslint-microsoft-contrib" + ] +} \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.skill.test.suite.js b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.skill.test.suite.js index 17623e3504..a920f873f5 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.skill.test.suite.js +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.skill.test.suite.js @@ -32,8 +32,10 @@ describe(`The generator-botbuilder-assistant skill tests`, function() { const templatesFiles = [ `package.json`, + `.eslintrc.js`, `.gitignore`, `.npmrc`, + `.nycrc`, manifestTemplatePath, dialogBotPath, mainDialogPath, diff --git a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.test.suite.js b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.test.suite.js index bf51d89b58..6df9bda82c 100644 --- a/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.test.suite.js +++ b/templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/test/generator-botbuilder-assistant.test.suite.js @@ -27,8 +27,10 @@ describe(`The generator-botbuilder-assistant tests`, function() { const templatesFiles = [ `package.json`, + `.eslintrc.js`, `.gitignore`, `.npmrc`, + `.nycrc`, dialogBotPath ]; const commonDirectories = [ diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/.eslintrc.js b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/.eslintrc.js new file mode 100644 index 0000000000..e791db9e2a --- /dev/null +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + plugins: [ + '@typescript-eslint', + '@typescript-eslint/tslint' + ], + extends: [ + 'plugin:@typescript-eslint/recommended' + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + project: './tsconfig.json' + }, + rules: { + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + 'args': 'none' + }], + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/interface-name-prefix': [ 'error', 'always' ], + '@typescript-eslint/no-angle-bracket-type-assertion': 'off', + '@typescript-eslint/tslint/config': [ + 'warn', + { + lintFile: './tslint.json' + } + ] + }, +}; \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package-lock.json b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package-lock.json index 21d221951b..a05b68c2bc 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package-lock.json +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package-lock.json @@ -376,6 +376,12 @@ "@types/node": "*" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@types/eslint-visitor-keys/-/@types/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-HuMNeVRMqE1o1LPNsK9PIFZj3S0=", + "dev": true + }, "@types/express": { "version": "4.17.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@types/express/-/@types/express-4.17.0.tgz", @@ -532,11 +538,86 @@ "@types/node": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/eslint-plugin/-/@typescript-eslint/eslint-plugin-1.11.0.tgz", + "integrity": "sha1-hw91LFINsE2202aK90eQJqby+5o=", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.11.0", + "eslint-utils": "^1.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", + "tsutils": "^3.7.0" + } + }, + "@typescript-eslint/eslint-plugin-tslint": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/eslint-plugin-tslint/-/@typescript-eslint/eslint-plugin-tslint-1.11.0.tgz", + "integrity": "sha1-LYN+OpSs9d4MLPqt9mP92422zlw=", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.11.0", + "lodash.memoize": "^4.1.2" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/experimental-utils/-/@typescript-eslint/experimental-utils-1.11.0.tgz", + "integrity": "sha1-WUq+RwkcvqusHW+c/tBtCtmet+M=", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "1.11.0", + "eslint-scope": "^4.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/parser/-/@typescript-eslint/parser-1.11.0.tgz", + "integrity": "sha1-L21PfmTusefCW0IvjfFNDJ5QjjY=", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "1.11.0", + "@typescript-eslint/typescript-estree": "1.11.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/typescript-estree/-/@typescript-eslint/typescript-estree-1.11.0.tgz", + "integrity": "sha1-t7V4Kqsi5LO22EYzZSyfQeYtN9U=", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/semver/-/semver-5.5.0.tgz", + "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=", + "dev": true + } + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=" }, + "acorn": { + "version": "6.1.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha1-fSWuBbuK0fm2mRCOEJTs14hK3B8=", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha1-MqBk/ZJUKSFqCbFBECv90YX65A4=", + "dev": true + }, "adal-node": { "version": "0.1.28", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/adal-node/-/adal-node-0.1.28.tgz", @@ -621,6 +702,12 @@ "integrity": "sha1-V9NbhoboUeLMBMQD8cACA5dqGBM=", "dev": true }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha1-h4C5j/nb9WOBUtHx/lwde0RCl2s=", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -756,6 +843,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", + "dev": true + }, "async": { "version": "2.6.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/async/-/async-2.6.0.tgz", @@ -1938,6 +2031,12 @@ } } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", + "dev": true + }, "camelcase": { "version": "4.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/camelcase/-/camelcase-4.1.0.tgz", @@ -1980,6 +2079,12 @@ "supports-color": "^2.0.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", + "dev": true + }, "charenc": { "version": "0.0.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/charenc/-/charenc-0.0.2.tgz", @@ -2046,6 +2151,21 @@ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cliui/-/cliui-4.1.0.tgz", @@ -2356,6 +2476,12 @@ "integrity": "sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=", "dev": true }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "default-require-extensions": { "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/default-require-extensions/-/default-require-extensions-2.0.0.tgz", @@ -2457,6 +2583,15 @@ "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "documentdb": { "version": "1.14.5", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/documentdb/-/documentdb-1.14.5.tgz", @@ -2644,11 +2779,192 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "5.16.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha1-oeOsGq5KP72Clvz496tzFMu2q+o=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/debug/-/debug-4.1.1.tgz", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/globals/-/globals-11.12.0.tgz", + "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ms/-/ms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/espree/-/espree-5.0.1.tgz", + "integrity": "sha1-XWUm+k/H8HiKXPdbFfMDI+L4H3o=", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esprima/-/esprima-4.0.1.tgz", "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=" }, + "esquery": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esutils/-/esutils-2.0.2.tgz", @@ -2739,6 +3055,17 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha1-WGbbKal4Jtvkvzr9JAcOrZ6kOic=", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "0.3.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/extglob/-/extglob-0.3.2.tgz", @@ -2783,6 +3110,30 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "filename-regex": { "version": "2.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/filename-regex/-/filename-regex-2.0.1.tgz", @@ -2873,6 +3224,23 @@ "is-buffer": "~2.0.3" } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha1-aeV8qo8OrLwoHS4stFjUb9tEngg=", + "dev": true + }, "follow-redirects": { "version": "1.5.10", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/follow-redirects/-/follow-redirects-1.5.10.tgz", @@ -2982,7 +3350,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3000,11 +3369,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3017,15 +3388,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3128,7 +3502,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3138,6 +3513,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3150,17 +3526,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3177,6 +3556,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3249,7 +3629,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3259,6 +3640,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3334,7 +3716,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3364,6 +3747,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3381,6 +3765,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3419,11 +3804,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -3432,6 +3819,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -3489,6 +3882,7 @@ "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "optional": true, "requires": { "is-glob": "^2.0.0" } @@ -3790,6 +4184,12 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -3810,6 +4210,16 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ignorepatterns/-/ignorepatterns-1.1.0.tgz", "integrity": "sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4=" }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha1-o9iX9CDKsOZxI2iX91vBS0iFw5A=", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3842,6 +4252,73 @@ "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", "dev": true }, + "inquirer": { + "version": "6.4.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/inquirer/-/inquirer-6.4.1.tgz", + "integrity": "sha1-e9nlqwVnzSO0GwGAto4M+oL8PAs=", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "int64-buffer": { "version": "0.1.10", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/int64-buffer/-/int64-buffer-0.1.10.tgz", @@ -3955,7 +4432,8 @@ "is-extglob": { "version": "1.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true }, "is-finite": { "version": "1.0.2", @@ -3975,6 +4453,7 @@ "version": "2.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -4046,6 +4525,12 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "optional": true }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-redirect/-/is-redirect-1.0.0.tgz", @@ -4313,6 +4798,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -4439,6 +4930,16 @@ "invert-kv": "^1.0.0" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "limiter": { "version": "1.1.4", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/limiter/-/limiter-1.1.4.tgz", @@ -4537,6 +5038,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.max/-/lodash.max-4.0.1.tgz", "integrity": "sha1-hzVWbGGLNan3YFILSHrnllivE2o=" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.once": { "version": "4.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.once/-/lodash.once-4.1.1.tgz", @@ -4557,6 +5064,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.trimend/-/lodash.trimend-4.5.1.tgz", "integrity": "sha1-EoBENyhrmMrYmWt5QU4RMAEUCC8=" }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/log-symbols/-/log-symbols-2.2.0.tgz", @@ -4861,9 +5374,9 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", + "version": "1.3.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -5210,9 +5723,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "ms-rest": { - "version": "2.5.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ms-rest/-/ms-rest-2.5.0.tgz", - "integrity": "sha1-1IPAA/fedwOt5rwZw7Qxmv+sJoc=", + "version": "2.5.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ms-rest/-/ms-rest-2.5.1.tgz", + "integrity": "sha1-I5E6taSctpKT7+KFDLISqmWmJ4A=", "requires": { "duplexer": "^0.1.1", "is-buffer": "^1.1.6", @@ -5254,6 +5767,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mustache/-/mustache-3.0.1.tgz", "integrity": "sha1-hzhV8jqoqVsVD7ltmDbtvFodJIo=" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "mv": { "version": "2.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mv/-/mv-2.1.1.tgz", @@ -5329,6 +5848,12 @@ } } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "ncp": { "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ncp/-/ncp-2.0.0.tgz", @@ -5875,6 +6400,7 @@ "version": "2.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -6287,6 +6813,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/optimist/-/optimist-0.6.1.tgz", @@ -6295,6 +6830,28 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "os-homedir": { @@ -6402,6 +6959,15 @@ "semver": "^5.1.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-glob": { "version": "3.0.4", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/parse-glob/-/parse-glob-3.0.4.tgz", @@ -6553,6 +7119,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prepend-http": { "version": "1.0.4", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/prepend-http/-/prepend-http-1.0.4.tgz", @@ -6585,6 +7157,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=" }, + "progress": { + "version": "2.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/progress/-/progress-2.0.3.tgz", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "dev": true + }, "promise.prototype.finally": { "version": "3.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz", @@ -7098,6 +7676,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", + "dev": true + }, "regexpu-core": { "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/regexpu-core/-/regexpu-core-2.0.0.tgz", @@ -7348,6 +7932,16 @@ "verror": "^1.8.1" } }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ret/-/ret-0.1.15.tgz", @@ -7367,6 +7961,24 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.4.tgz", "integrity": "sha1-NipCxtMEBW1JOz8SvOq7LGV2ptQ=" }, + "run-async": { + "version": "2.3.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha1-LjXOgVzUbYTQKiCftOWSHgUdvsc=", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7450,9 +8062,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -7501,6 +8113,28 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/slash/-/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/snapdragon/-/snapdragon-0.8.2.tgz", @@ -7866,6 +8500,46 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, + "table": { + "version": "5.4.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/table/-/table-5.4.1.tgz", + "integrity": "sha1-BpGuLr6CWYWO+2PlULbV+TABceg=", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "taskgroup": { "version": "4.3.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/taskgroup/-/taskgroup-4.3.1.tgz", @@ -7904,6 +8578,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/through/-/through-2.3.8.tgz", @@ -7925,6 +8605,15 @@ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "dev": true }, + "tmp": { + "version": "0.0.33", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -8064,13 +8753,22 @@ "requires": { "has-flag": "^3.0.0" } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } } } }, "tslint-microsoft-contrib": { - "version": "6.0.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.0.0.tgz", - "integrity": "sha1-e/9zya16C361zbBJBt5Y9Cor96I=", + "version": "6.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.2.0.tgz", + "integrity": "sha1-iqD0BYTQZtBeal55iNpRY7hfKtQ=", "dev": true, "requires": { "tsutils": "^2.27.2 <2.29.0" @@ -8088,9 +8786,9 @@ } }, "tsutils": { - "version": "2.29.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", + "version": "3.14.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tsutils/-/tsutils-3.14.0.tgz", + "integrity": "sha1-v41ae65TaTMfoPKwpaEL1/c5bHc=", "dev": true, "requires": { "tslib": "^1.8.1" @@ -8114,6 +8812,15 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-check": { + "version": "0.3.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/type-detect/-/type-detect-4.0.8.tgz", @@ -8176,35 +8883,14 @@ "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" }, "union-value": { - "version": "1.0.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unique-string": { @@ -8537,9 +9223,9 @@ } }, "wordwrap": { - "version": "0.0.3", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, "wrap-ansi": { @@ -8579,6 +9265,15 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/write/-/write-1.0.3.tgz", + "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package.json b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package.json index 643934d6d1..cdc7683120 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package.json +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/package.json @@ -10,8 +10,8 @@ "copy-templates": "copyfiles --up 1 \"./src/**/*.json\" \"./lib\"", "prebuild": "npm run lint", "build": "tsc --p tsconfig.json && npm run copy-templates", - "lint": "tslint -t vso ./src/**/*.ts", - "lint-fix": "tslint --fix ./src/**/*.ts", + "lint": "eslint ./src/**/*.ts", + "lint-fix": "eslint --fix ./src/**/*.ts", "start": "npm run build && node ./lib/index.js NODE_ENV=development", "watch": "nodemon ./lib/index.js NODE_ENV=development", "test": "mocha", @@ -39,7 +39,11 @@ "devDependencies": { "@types/i18next-node-fs-backend": "^0.0.30", "@types/restify": "^7.2.4", + "@typescript-eslint/eslint-plugin": "^1.10.2", + "@typescript-eslint/eslint-plugin-tslint": "^1.10.2", + "@typescript-eslint/parser": "^1.10.2", "copyfiles": "^2.1.0", + "eslint": "^5.16.0", "mocha": "^6.1.4", "mocha-junit-reporter": "^1.22.0", "nock": "^10.0.6", @@ -47,7 +51,7 @@ "nyc": "^14.1.1", "rimraf": "^2.6.2", "tslint": "^5.12.1", - "tslint-microsoft-contrib": "6.0.0", + "tslint-microsoft-contrib": "^6.0.0", "typescript": "^3.2.2" }, "env": { diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/adapters/defaultAdapter.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/adapters/defaultAdapter.ts index c584abb8c7..15ae991eb6 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/adapters/defaultAdapter.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/adapters/defaultAdapter.ts @@ -32,7 +32,7 @@ export class DefaultAdapter extends BotFrameworkAdapter { public readonly skills: ISkillManifest[] = []; public readonly userState: UserState; - constructor( + public constructor( settings: Partial, adapterSettings: Partial, telemetryClient: BotTelemetryClient diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/bots/dialogBot.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/bots/dialogBot.ts index 7142d65028..c92b5ae63d 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/bots/dialogBot.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/bots/dialogBot.ts @@ -14,8 +14,7 @@ import { Dialog, DialogContext, DialogSet, - DialogState, - DialogTurnResult } from 'botbuilder-dialogs'; + DialogState } from 'botbuilder-dialogs'; export class DialogBot extends ActivityHandler { private readonly telemetryClient: BotTelemetryClient; @@ -23,7 +22,7 @@ export class DialogBot extends ActivityHandler { private readonly rootDialogId: string; private readonly dialogs: DialogSet; - constructor( + public constructor( conversationState: ConversationState, telemetryClient: BotTelemetryClient, dialog: T) { @@ -36,7 +35,7 @@ export class DialogBot extends ActivityHandler { this.onTurn(this.turn.bind(this)); } - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public async turn(turnContext: TurnContext, next: () => Promise): Promise { // Client notifying this bot took to long to respond (timed out) if (turnContext.activity.code === EndOfConversationCodes.BotTimedOut) { @@ -51,7 +50,7 @@ export class DialogBot extends ActivityHandler { const dc: DialogContext = await this.dialogs.createContext(turnContext); if (dc.activeDialog !== undefined) { - const result: DialogTurnResult = await dc.continueDialog(); + await dc.continueDialog(); } else { await dc.beginDialog(this.rootDialogId); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/cancelDialog.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/cancelDialog.ts index 818e39efab..8845533470 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/cancelDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/cancelDialog.ts @@ -22,7 +22,7 @@ export class CancelDialog extends ComponentDialog { private readonly responder: CancelResponses = new CancelResponses(); // Constructor - constructor() { + public constructor() { super(CancelDialog.name); this.initialDialogId = CancelDialog.name; diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/escalateDialog.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/escalateDialog.ts index add07daed6..911047680b 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/escalateDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/escalateDialog.ts @@ -17,7 +17,7 @@ export class EscalateDialog extends ComponentDialog { private readonly responder: EscalateResponses = new EscalateResponses(); // Constructor - constructor(botServices: BotServices, telemetryClient: BotTelemetryClient) { + public constructor(botServices: BotServices, telemetryClient: BotTelemetryClient) { super(EscalateDialog.name); this.initialDialogId = EscalateDialog.name; const escalate: ((sc: WaterfallStepContext) => Promise)[] = [ diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/mainDialog.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/mainDialog.ts index 1d762ac788..906d575625 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/mainDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/mainDialog.ts @@ -47,7 +47,7 @@ export class MainDialog extends RouterDialog { private readonly responder: MainResponses = new MainResponses(); // Constructor - constructor( + public constructor( settings: Partial, services: BotServices, onboardingDialog: OnboardingDialog, @@ -67,7 +67,7 @@ export class MainDialog extends RouterDialog { this.addDialog(escalateDialog); this.addDialog(cancelDialog); - skillDialogs.forEach((skillDialog: SkillDialog) => { + skillDialogs.forEach((skillDialog: SkillDialog): void => { this.addDialog(skillDialog); }); } @@ -228,7 +228,7 @@ export class MainDialog extends RouterDialog { const intent: string = LuisRecognizer.topIntent(luisResult); // Only triggers interruption if confidence level is high - if (luisResult.intents[intent] && luisResult.intents[intent].score > 0.5) { + if (luisResult.intents[intent] !== undefined && luisResult.intents[intent].score > 0.5) { switch (intent) { case 'Cancel': { return this.onCancel(dc); @@ -284,7 +284,7 @@ export class MainDialog extends RouterDialog { // Sign out user // PENDING check adapter.getTokenStatusAsync const tokens: TokenStatus[] = []; - tokens.forEach(async (token: TokenStatus) => { + tokens.forEach(async (token: TokenStatus): Promise => { if (token.connectionName !== undefined) { await adapter.signOutUser(dc.context, token.connectionName); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/onboardingDialog.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/onboardingDialog.ts index 0bab821fe0..a943101e93 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/onboardingDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/dialogs/onboardingDialog.ts @@ -30,7 +30,7 @@ export class OnboardingDialog extends ComponentDialog { private state!: IOnboardingState; // Constructor - constructor(botServices: BotServices, accessor: StatePropertyAccessor, telemetryClient: BotTelemetryClient) { + public constructor(botServices: BotServices, accessor: StatePropertyAccessor, telemetryClient: BotTelemetryClient) { super(OnboardingDialog.name); this.accessor = accessor; this.initialDialogId = OnboardingDialog.name; @@ -91,4 +91,4 @@ export class OnboardingDialog extends ComponentDialog { return state; } - } +} diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/index.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/index.ts index 8ac8f0ea6d..8dfc51fa2d 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/index.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/index.ts @@ -18,6 +18,7 @@ import { Locales, MultiProviderAuthDialog } from 'botbuilder-solutions'; import i18next from 'i18next'; +// tslint:disable-next-line: match-default-export-name import i18nextNodeFsBackend from 'i18next-node-fs-backend'; import * as path from 'path'; import * as restify from 'restify'; @@ -35,23 +36,24 @@ import { IBotSettings } from './services/botSettings'; import { skills as skillsRaw } from './skills.json'; // Configure internationalization and default locale +// tslint:disable-next-line: no-floating-promises i18next.use(i18nextNodeFsBackend) -.init({ - fallbackLng: 'en', - preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ], - backend: { - loadPath: path.join(__dirname, 'locales', '{{lng}}.json') - } -}) -.then(async () => { - await Locales.addResourcesFromPath(i18next, 'common'); -}); + .init({ + fallbackLng: 'en', + preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ], + backend: { + loadPath: path.join(__dirname, 'locales', '{{lng}}.json') + } + }) + .then(async (): Promise => { + await Locales.addResourcesFromPath(i18next, 'common'); + }); const skills: ISkillManifest[] = skillsRaw; const cognitiveModels: Map = new Map(); const cognitiveModelDictionary: { [key: string]: Object } = cognitiveModelsRaw.cognitiveModels; const cognitiveModelMap: Map = new Map(Object.entries(cognitiveModelDictionary)); -cognitiveModelMap.forEach((value: Object, key: string) => { +cognitiveModelMap.forEach((value: Object, key: string): void => { cognitiveModels.set(key, value); }); @@ -67,7 +69,7 @@ const botSettings: Partial = { }; function getTelemetryClient(settings: Partial): BotTelemetryClient { - if (settings && settings.appInsights && settings.appInsights.instrumentationKey) { + if (settings !== undefined && settings.appInsights !== undefined && settings.appInsights.instrumentationKey !== undefined) { const instrumentationKey: string = settings.appInsights.instrumentationKey; return new ApplicationInsightsTelemetryClient(instrumentationKey); @@ -96,7 +98,7 @@ try { const onboardingDialog: OnboardingDialog = new OnboardingDialog(botServices, onboardingStateAccessor, telemetryClient); const escalateDialog: EscalateDialog = new EscalateDialog(botServices, telemetryClient); const cancelDialog: CancelDialog = new CancelDialog(); - const skillDialogs: SkillDialog[] = skills.map((skill: ISkillManifest) => { + const skillDialogs: SkillDialog[] = skills.map((skill: ISkillManifest): SkillDialog => { const authDialog: MultiProviderAuthDialog|undefined = buildAuthDialog(skill, botSettings); const credentials: MicrosoftAppCredentialsEx = new MicrosoftAppCredentialsEx( botSettings.microsoftAppId || '', @@ -127,6 +129,7 @@ const server: restify.Server = restify.createServer(); // Enable the Application Insights middleware, which helps correlate all activity // based on the incoming request. server.use(restify.plugins.bodyParser()); +// tslint:disable-next-line:no-unsafe-any server.use(ApplicationInsightsWebserverMiddleware); server.listen(process.env.port || process.env.PORT || '3979', (): void => { @@ -139,9 +142,9 @@ server.listen(process.env.port || process.env.PORT || '3979', (): void => { }); // Listen for incoming requests -server.post('/api/messages', (req: restify.Request, res: restify.Response) => { +server.post('/api/messages', async (req: restify.Request, res: restify.Response): Promise => { // Route received a request to adapter for processing - adapter.processActivity(req, res, async (turnContext: TurnContext) => { + await adapter.processActivity(req, res, async (turnContext: TurnContext): Promise => { // route to bot activity handler. await bot.run(turnContext); }); @@ -152,11 +155,11 @@ function buildAuthDialog(skill: ISkillManifest, settings: Partial) if (skill.authenticationConnections !== undefined && skill.authenticationConnections.length > 0) { if (settings.oauthConnections !== undefined) { const oauthConnections: IOAuthConnection[] | undefined = settings.oauthConnections.filter( - (oauthConnection: IOAuthConnection) => { - return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection) => { - return authenticationConnection.serviceProviderId === oauthConnection.provider; + (oauthConnection: IOAuthConnection): boolean => { + return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection): boolean => { + return authenticationConnection.serviceProviderId === oauthConnection.provider; + }); }); - }); if (oauthConnections !== undefined) { return new MultiProviderAuthDialog(oauthConnections); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/cancelResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/cancelResponses.ts index 1be49baa67..dd95764878 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/cancelResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/cancelResponses.ts @@ -36,7 +36,7 @@ export class CancelResponses extends TemplateManager { ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(CancelResponses.responseTemplates)); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/escalateResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/escalateResponses.ts index 4b52a6a6d3..d2be3f7e7e 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/escalateResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/escalateResponses.ts @@ -20,7 +20,7 @@ export class EscalateResponses extends TemplateManager { // Declare here the type of properties and the prompts public static responseIds: { - sendPhoneMessage : string; + sendPhoneMessage: string; } = { sendPhoneMessage: 'sendPhoneMessage' }; @@ -28,19 +28,21 @@ export class EscalateResponses extends TemplateManager { // Declare the responses map prompts private static readonly responseTemplates: LanguageTemplateDictionary = new Map([ ['default', new Map([ - [EscalateResponses.responseIds.sendPhoneMessage, - // tslint:disable-next-line: no-any - (context: TurnContext, data: any): Promise => EscalateResponses.buildEscalateCard(context, data)] + [ + EscalateResponses.responseIds.sendPhoneMessage, + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + (context: TurnContext, data: any): Promise => EscalateResponses.buildEscalateCard(context, data) + ] ])] ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(EscalateResponses.responseTemplates)); } - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildEscalateCard(turnContext: TurnContext, data: any): Promise { const response: Activity = ActivityExtensions.createReply(turnContext.activity); diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/mainResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/mainResponses.ts index b756ef9f61..8d8bda4a8c 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/mainResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/mainResponses.ts @@ -11,6 +11,7 @@ import { MessageFactory, TurnContext } from 'botbuilder'; import { ActionTypes } from 'botframework-schema'; +import { readFileSync } from 'fs'; import i18next from 'i18next'; import { join } from 'path'; import { @@ -54,18 +55,19 @@ export class MainResponses extends TemplateManager { ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(MainResponses.responseTemplates)); } - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildNewUserGreetingCard(turnContext: TurnContext, data: any): Promise { const introFileName: string = i18next.t('main.introGreetingFile'); const introPath: string = join(__dirname, '..', 'content', introFileName); - // tslint:disable-next-line:no-any non-literal-require - const introCard: any = require(introPath); + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + const introCard: any = JSON.parse(readFileSync(introPath, 'UTF8')); const attachment: Attachment = CardFactory.adaptiveCard(introCard); + // eslint-disable-next-line @typescript-eslint/tslint/config const response: Partial = MessageFactory.attachment(attachment, '', attachment.content.speak, InputHints.AcceptingInput); response.suggestedActions = { @@ -92,13 +94,14 @@ export class MainResponses extends TemplateManager { return Promise.resolve(response); } - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildReturningUserGreetingCard(turnContext: TurnContext, data: any): Promise { const introFileName: string = i18next.t('main.introReturningFile'); const introPath: string = join(__dirname, '..', 'content', introFileName); - // tslint:disable-next-line:no-any non-literal-require - const introCard: any = require(introPath); + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + const introCard: any = JSON.parse(readFileSync(introPath, 'UTF8')); const attachment: Attachment = CardFactory.adaptiveCard(introCard); + // eslint-disable-next-line @typescript-eslint/tslint/config const response: Partial = MessageFactory.attachment(attachment, '', attachment.content.speak, InputHints.AcceptingInput); response.suggestedActions = { @@ -125,7 +128,7 @@ export class MainResponses extends TemplateManager { return Promise.resolve(response); } - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public static async buildHelpCard(turnContext: TurnContext, data: any): Promise { const title: string = i18next.t('main.helpTitle'); const text: string = i18next.t('main.helpText'); @@ -134,21 +137,21 @@ export class MainResponses extends TemplateManager { response.suggestedActions = { actions: [ - { - title: i18next.t('main.helpBtnText1'), - type: ActionTypes.ImBack, - value: i18next.t('main.helpBtnValue1') - }, - { - title: i18next.t('main.helpBtnText2'), - type: ActionTypes.ImBack, - value: i18next.t('main.helpBtnValue2') - }, - { - title: i18next.t('main.helpBtnText3'), - type: ActionTypes.OpenUrl, - value: i18next.t('main.helpBtnValue3') - } + { + title: i18next.t('main.helpBtnText1'), + type: ActionTypes.ImBack, + value: i18next.t('main.helpBtnValue1') + }, + { + title: i18next.t('main.helpBtnText2'), + type: ActionTypes.ImBack, + value: i18next.t('main.helpBtnValue2') + }, + { + title: i18next.t('main.helpBtnText3'), + type: ActionTypes.OpenUrl, + value: i18next.t('main.helpBtnValue3') + } ], to: [] }; diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/onboardingResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/onboardingResponses.ts index 828a0b630b..3603ef0220 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/onboardingResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/responses/onboardingResponses.ts @@ -15,9 +15,9 @@ export class OnboardingResponses extends TemplateManager { // Declare here the type of properties and the prompts public static responseIds: { - emailPrompt : string; - haveEmailMessage : string; - haveNameMessage : string; + emailPrompt: string; + haveEmailMessage: string; + haveNameMessage: string; haveLocationMessage: string; locationPrompt: string; namePrompt: string; @@ -34,23 +34,23 @@ export class OnboardingResponses extends TemplateManager { private static readonly responseTemplates: LanguageTemplateDictionary = new Map([ ['default', new Map([ [OnboardingResponses.responseIds.emailPrompt, OnboardingResponses.fromResources('onboarding.emailPrompt')], - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config [OnboardingResponses.responseIds.haveEmailMessage, async (context: TurnContext, data: any): Promise => { const value: string = i18next.t('onboarding.haveEmail'); // tslint:disable-next-line: no-unsafe-any return value.replace('{0}', data.email); }], - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config [OnboardingResponses.responseIds.haveLocationMessage, async (context: TurnContext, data: any): Promise => { const value: string = i18next.t('onboarding.haveLocation'); // tslint:disable-next-line: no-unsafe-any return value.replace('{0}', data.name) - // tslint:disable-next-line: no-unsafe-any - .replace('{1}', data.location); + // tslint:disable-next-line: no-unsafe-any + .replace('{1}', data.location); }], - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config [OnboardingResponses.responseIds.haveNameMessage, async (context: TurnContext, data: any): Promise => { const value: string = i18next.t('onboarding.haveName'); @@ -63,7 +63,7 @@ export class OnboardingResponses extends TemplateManager { ]); // Initialize the responses class properties - constructor() { + public constructor() { super(); this.register(new DictionaryRenderer(OnboardingResponses.responseTemplates)); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/services/botServices.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/services/botServices.ts index 8d137c2f46..966760dc33 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/services/botServices.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/services/botServices.ts @@ -13,14 +13,14 @@ export class BotServices { public cognitiveModelSets: Map = new Map(); - constructor(settings: Partial, telemetryClient: BotTelemetryClient) { + public constructor(settings: Partial, telemetryClient: BotTelemetryClient) { const luisPredictionOptions: LuisPredictionOptions = { telemetryClient: telemetryClient, logPersonalInformation: true }; if (settings.cognitiveModels !== undefined) { - settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string) => { + settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string): void => { const language: string = key; const config: ICognitiveModelConfiguration = value; @@ -39,7 +39,7 @@ export class BotServices { }; if (config.languageModels !== undefined) { - config.languageModels.forEach((model: LuisService) => { + config.languageModels.forEach((model: LuisService): void => { const luisService: LuisService = new LuisService(model); const luisApp: LuisApplication = { applicationId: luisService.appId, @@ -50,7 +50,7 @@ export class BotServices { }); } - config.knowledgeBases.forEach((kb: QnaMakerService) => { + config.knowledgeBases.forEach((kb: QnaMakerService): void => { const qnaEndpoint: QnAMakerEndpoint = { knowledgeBaseId: kb.kbId, endpointKey: kb.endpointKey, diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/dictionaryRenderer.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/dictionaryRenderer.ts index d7ec2aab01..a04f77d6a5 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/dictionaryRenderer.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/dictionaryRenderer.ts @@ -6,7 +6,7 @@ import { TurnContext } from 'botbuilder-core'; import { ITemplateRenderer } from './templateRenderer'; -// tslint:disable-next-line:no-any +// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config export declare type TemplateFunction = (turnContext: TurnContext, data: any) => Promise; /** @@ -34,17 +34,17 @@ export declare type LanguageTemplateDictionary = Map { const templates: TemplateIdMap | undefined = this.languages.get(language); if (templates !== undefined) { const template: TemplateFunction | undefined = templates.get(templateId); if (template !== undefined) { - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const result: Promise = template(turnContext, data); if (result !== undefined) { return result; diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/graphClient.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/graphClient.ts index e57565df3b..2332a78adf 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/graphClient.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/graphClient.ts @@ -12,21 +12,25 @@ import { User } from '@microsoft/microsoft-graph-types'; export class GraphClient { private readonly token: string; - constructor(token: string) { + public constructor(token: string) { this.token = token; } - public getMe(): Promise { - // tslint:disable-next-line:no-any - return new Promise((resolve: (value?: User | PromiseLike | undefined) => any, reject: (reason?: any) => void): void => { + public async getMe(): Promise { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + return new Promise((resolve, reject): Promise => { const client: Client = this.getAuthenticatedClient(); - client.api('/me') - .select('displayName') - .get((err: GraphError, res: User) => { - if (err) { return reject(err); } - return resolve(res); - }); + return client + .api('/me') + .select('displayName') + .get((err: GraphError, res: User): void => { + if (err !== undefined) { + reject(err); + } + + resolve(res); + }); }); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateManager.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateManager.ts index 16e642357d..a76541809b 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateManager.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateManager.ts @@ -17,7 +17,7 @@ export class TemplateManager { * Add a template engine for binding templates */ public register(renderer: ITemplateRenderer): TemplateManager { - if (!this.templateRenders.some((x: ITemplateRenderer) => x === renderer)) { + if (!this.templateRenders.some((x: ITemplateRenderer): boolean => x === renderer)) { this.templateRenders.push(renderer); } @@ -42,7 +42,7 @@ export class TemplateManager { /** * Send a reply with the template */ - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public async replyWith(turnContext: TurnContext, templateId: string, data?: any): Promise { if (turnContext === undefined) { throw new Error('turnContext is null'); } @@ -57,10 +57,13 @@ export class TemplateManager { return; } - public async renderTemplate(turnContext: TurnContext, - templateId: string, - // tslint:disable-next-line:no-any - language?: string, data?: any): Promise { + public async renderTemplate( + turnContext: TurnContext, + templateId: string, + language?: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config + data?: any + ): Promise { const fallbackLocales: string[] = this.languageFallback; if (language !== undefined) { @@ -72,11 +75,11 @@ export class TemplateManager { // try each locale until successful for (const locale of fallbackLocales) { for (const renderer of this.templateRenders) { - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const templateOutput: any = await renderer.renderTemplate(turnContext, locale, templateId, data); if (templateOutput) { if (typeof templateOutput === 'string' || templateOutput instanceof String) { - const def : Partial = { type: ActivityTypes.Message, text: templateOutput}; + const def: Partial = { type: ActivityTypes.Message, text: templateOutput}; return def; } else { diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateRenderer.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateRenderer.ts index 3ea1cda8c0..d7a975060d 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateRenderer.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/src/templateManager/templateRenderer.ts @@ -17,6 +17,6 @@ export interface ITemplateRenderer { * @param templateId - template to render * @param data - data object to use to render */ - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config renderTemplate(turnContext: TurnContext, language: string, templateId: string, data: any): Promise; } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/tslint.json b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/tslint.json index 46630b8017..91c8a37d7d 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/tslint.json +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/tslint.json @@ -17,20 +17,26 @@ "static-method-regex": "^[a-z][\\w\\d]+$" } ], - "linebreak-style": [ - false - ], - "member-ordering": [ - false - ], - "no-relative-imports": [ - false + "strict-boolean-expressions": [ + true, + "allow-undefined-union", + "allow-null-union", + "allow-mix", + "allow-string", + "ignore-rhs" ], - "completed-docs": [ - false - ] + "linebreak-style": false, + "completed-docs": false, + "no-relative-imports": false, + "export-name": false, + "member-ordering": false, + "no-use-before-declare": false, + "no-function-constructor-with-string-args": false, + "no-reserved-keywords": false, + "no-increment-decrement": false, + "no-unnecessary-bind": false }, "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" + "tslint-microsoft-contrib" ] } \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/.eslintrc.js b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/.eslintrc.js new file mode 100644 index 0000000000..e791db9e2a --- /dev/null +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/.eslintrc.js @@ -0,0 +1,33 @@ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + plugins: [ + '@typescript-eslint', + '@typescript-eslint/tslint' + ], + extends: [ + 'plugin:@typescript-eslint/recommended' + ], + parserOptions: { + ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + project: './tsconfig.json' + }, + rules: { + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + 'args': 'none' + }], + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/interface-name-prefix': [ 'error', 'always' ], + '@typescript-eslint/no-angle-bracket-type-assertion': 'off', + '@typescript-eslint/tslint/config': [ + 'warn', + { + lintFile: './tslint.json' + } + ] + }, +}; \ No newline at end of file diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package-lock.json b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package-lock.json index 749f446a38..3f08852556 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package-lock.json +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package-lock.json @@ -396,6 +396,12 @@ "@types/node": "*" } }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@types/eslint-visitor-keys/-/@types/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-HuMNeVRMqE1o1LPNsK9PIFZj3S0=", + "dev": true + }, "@types/express": { "version": "4.17.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@types/express/-/@types/express-4.17.0.tgz", @@ -552,11 +558,86 @@ "@types/node": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/eslint-plugin/-/@typescript-eslint/eslint-plugin-1.11.0.tgz", + "integrity": "sha1-hw91LFINsE2202aK90eQJqby+5o=", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.11.0", + "eslint-utils": "^1.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^2.0.1", + "tsutils": "^3.7.0" + } + }, + "@typescript-eslint/eslint-plugin-tslint": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/eslint-plugin-tslint/-/@typescript-eslint/eslint-plugin-tslint-1.11.0.tgz", + "integrity": "sha1-LYN+OpSs9d4MLPqt9mP92422zlw=", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "1.11.0", + "lodash.memoize": "^4.1.2" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/experimental-utils/-/@typescript-eslint/experimental-utils-1.11.0.tgz", + "integrity": "sha1-WUq+RwkcvqusHW+c/tBtCtmet+M=", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "1.11.0", + "eslint-scope": "^4.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/parser/-/@typescript-eslint/parser-1.11.0.tgz", + "integrity": "sha1-L21PfmTusefCW0IvjfFNDJ5QjjY=", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "1.11.0", + "@typescript-eslint/typescript-estree": "1.11.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.11.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/@typescript-eslint/typescript-estree/-/@typescript-eslint/typescript-estree-1.11.0.tgz", + "integrity": "sha1-t7V4Kqsi5LO22EYzZSyfQeYtN9U=", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/semver/-/semver-5.5.0.tgz", + "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=", + "dev": true + } + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=" }, + "acorn": { + "version": "6.1.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha1-fSWuBbuK0fm2mRCOEJTs14hK3B8=", + "dev": true + }, + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha1-MqBk/ZJUKSFqCbFBECv90YX65A4=", + "dev": true + }, "adal-node": { "version": "0.1.28", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/adal-node/-/adal-node-0.1.28.tgz", @@ -641,6 +722,12 @@ "integrity": "sha1-V9NbhoboUeLMBMQD8cACA5dqGBM=", "dev": true }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha1-h4C5j/nb9WOBUtHx/lwde0RCl2s=", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -776,6 +863,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", + "dev": true + }, "async": { "version": "2.6.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/async/-/async-2.6.0.tgz", @@ -1684,9 +1777,9 @@ } }, "botbuilder-skills": { - "version": "1.0.6-preview77", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/botbuilder-skills/-/botbuilder-skills-1.0.6-preview77.tgz", - "integrity": "sha1-4lGIWqZNx3QArTuGwURzkRqKgk4=", + "version": "1.0.6-preview78", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/botbuilder-skills/-/botbuilder-skills-1.0.6-preview78.tgz", + "integrity": "sha1-XJ6RtFhwGUsLguNgIkgv+NlQks4=", "requires": { "@azure/cognitiveservices-luis-authoring": "^2.1.0", "@azure/ms-rest-js": "1.8.7", @@ -1985,6 +2078,12 @@ } } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", + "dev": true + }, "camelcase": { "version": "4.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/camelcase/-/camelcase-4.1.0.tgz", @@ -2027,6 +2126,12 @@ "supports-color": "^2.0.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", + "dev": true + }, "charenc": { "version": "0.0.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/charenc/-/charenc-0.0.2.tgz", @@ -2093,6 +2198,21 @@ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cliui/-/cliui-4.1.0.tgz", @@ -2409,6 +2529,12 @@ "integrity": "sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=", "dev": true }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "default-require-extensions": { "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/default-require-extensions/-/default-require-extensions-2.0.0.tgz", @@ -2510,6 +2636,15 @@ "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "documentdb": { "version": "1.14.5", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/documentdb/-/documentdb-1.14.5.tgz", @@ -2689,11 +2824,192 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "5.16.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha1-oeOsGq5KP72Clvz496tzFMu2q+o=", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/debug/-/debug-4.1.1.tgz", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/globals/-/globals-11.12.0.tgz", + "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ms/-/ms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha1-ygODMxD2iJoyZHgaqC5j65z+eEg=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/espree/-/espree-5.0.1.tgz", + "integrity": "sha1-XWUm+k/H8HiKXPdbFfMDI+L4H3o=", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esprima/-/esprima-4.0.1.tgz", "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=" }, + "esquery": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/esutils/-/esutils-2.0.2.tgz", @@ -2784,6 +3100,17 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha1-WGbbKal4Jtvkvzr9JAcOrZ6kOic=", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "0.3.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/extglob/-/extglob-0.3.2.tgz", @@ -2828,6 +3155,30 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "filename-regex": { "version": "2.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/filename-regex/-/filename-regex-2.0.1.tgz", @@ -2918,6 +3269,23 @@ "is-buffer": "~2.0.3" } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha1-aeV8qo8OrLwoHS4stFjUb9tEngg=", + "dev": true + }, "follow-redirects": { "version": "1.5.10", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/follow-redirects/-/follow-redirects-1.5.10.tgz", @@ -3027,7 +3395,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3045,11 +3414,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3062,15 +3433,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3173,7 +3547,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3183,6 +3558,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3195,17 +3571,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3222,6 +3601,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3294,7 +3674,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3304,6 +3685,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3379,7 +3761,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3409,6 +3792,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3426,6 +3810,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3464,11 +3849,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -3477,6 +3864,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -3534,6 +3927,7 @@ "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "optional": true, "requires": { "is-glob": "^2.0.0" } @@ -3835,6 +4229,12 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -3855,6 +4255,16 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ignorepatterns/-/ignorepatterns-1.1.0.tgz", "integrity": "sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4=" }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha1-o9iX9CDKsOZxI2iX91vBS0iFw5A=", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3887,6 +4297,73 @@ "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", "dev": true }, + "inquirer": { + "version": "6.4.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/inquirer/-/inquirer-6.4.1.tgz", + "integrity": "sha1-e9nlqwVnzSO0GwGAto4M+oL8PAs=", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "int64-buffer": { "version": "0.1.10", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/int64-buffer/-/int64-buffer-0.1.10.tgz", @@ -4000,7 +4477,8 @@ "is-extglob": { "version": "1.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "optional": true }, "is-finite": { "version": "1.0.2", @@ -4020,6 +4498,7 @@ "version": "2.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "optional": true, "requires": { "is-extglob": "^1.0.0" } @@ -4091,6 +4570,12 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "optional": true }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/is-redirect/-/is-redirect-1.0.0.tgz", @@ -4349,6 +4834,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -4475,6 +4966,16 @@ "invert-kv": "^1.0.0" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "limiter": { "version": "1.1.4", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/limiter/-/limiter-1.1.4.tgz", @@ -4573,6 +5074,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.max/-/lodash.max-4.0.1.tgz", "integrity": "sha1-hzVWbGGLNan3YFILSHrnllivE2o=" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.once": { "version": "4.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.once/-/lodash.once-4.1.1.tgz", @@ -4593,6 +5100,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.trimend/-/lodash.trimend-4.5.1.tgz", "integrity": "sha1-EoBENyhrmMrYmWt5QU4RMAEUCC8=" }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "log-symbols": { "version": "2.2.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/log-symbols/-/log-symbols-2.2.0.tgz", @@ -5246,9 +5759,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "ms-rest": { - "version": "2.5.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ms-rest/-/ms-rest-2.5.0.tgz", - "integrity": "sha1-1IPAA/fedwOt5rwZw7Qxmv+sJoc=", + "version": "2.5.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ms-rest/-/ms-rest-2.5.1.tgz", + "integrity": "sha1-I5E6taSctpKT7+KFDLISqmWmJ4A=", "requires": { "duplexer": "^0.1.1", "is-buffer": "^1.1.6", @@ -5290,6 +5803,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mustache/-/mustache-3.0.1.tgz", "integrity": "sha1-hzhV8jqoqVsVD7ltmDbtvFodJIo=" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "mv": { "version": "2.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/mv/-/mv-2.1.1.tgz", @@ -5365,6 +5884,12 @@ } } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "ncp": { "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ncp/-/ncp-2.0.0.tgz", @@ -5907,6 +6432,7 @@ "version": "2.1.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -6319,6 +6845,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/optimist/-/optimist-0.6.1.tgz", @@ -6327,6 +6862,28 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "os-homedir": { @@ -6434,6 +6991,15 @@ "semver": "^5.1.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-glob": { "version": "3.0.4", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/parse-glob/-/parse-glob-3.0.4.tgz", @@ -6585,6 +7151,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prepend-http": { "version": "1.0.4", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/prepend-http/-/prepend-http-1.0.4.tgz", @@ -6617,6 +7189,12 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=" }, + "progress": { + "version": "2.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/progress/-/progress-2.0.3.tgz", + "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "dev": true + }, "promise.prototype.finally": { "version": "3.1.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz", @@ -7130,6 +7708,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", + "dev": true + }, "regexpu-core": { "version": "2.0.0", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/regexpu-core/-/regexpu-core-2.0.0.tgz", @@ -7552,6 +8136,16 @@ "verror": "^1.8.1" } }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ret/-/ret-0.1.15.tgz", @@ -7571,6 +8165,24 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.4.tgz", "integrity": "sha1-NipCxtMEBW1JOz8SvOq7LGV2ptQ=" }, + "run-async": { + "version": "2.3.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha1-LjXOgVzUbYTQKiCftOWSHgUdvsc=", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7705,6 +8317,28 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/slash/-/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/snapdragon/-/snapdragon-0.8.2.tgz", @@ -8070,6 +8704,46 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, + "table": { + "version": "5.4.1", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/table/-/table-5.4.1.tgz", + "integrity": "sha1-BpGuLr6CWYWO+2PlULbV+TABceg=", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "taskgroup": { "version": "4.3.1", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/taskgroup/-/taskgroup-4.3.1.tgz", @@ -8108,6 +8782,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/through/-/through-2.3.8.tgz", @@ -8129,6 +8809,15 @@ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "dev": true }, + "tmp": { + "version": "0.0.33", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -8268,13 +8957,22 @@ "requires": { "has-flag": "^3.0.0" } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } } } }, "tslint-microsoft-contrib": { - "version": "6.0.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.0.0.tgz", - "integrity": "sha1-e/9zya16C361zbBJBt5Y9Cor96I=", + "version": "6.2.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.2.0.tgz", + "integrity": "sha1-iqD0BYTQZtBeal55iNpRY7hfKtQ=", "dev": true, "requires": { "tsutils": "^2.27.2 <2.29.0" @@ -8292,9 +8990,9 @@ } }, "tsutils": { - "version": "2.29.0", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha1-MrSIUBRnrL7dS4VJhnOggSrKC5k=", + "version": "3.14.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tsutils/-/tsutils-3.14.0.tgz", + "integrity": "sha1-v41ae65TaTMfoPKwpaEL1/c5bHc=", "dev": true, "requires": { "tslib": "^1.8.1" @@ -8318,6 +9016,15 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-check": { + "version": "0.3.2", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/type-detect/-/type-detect-4.0.8.tgz", @@ -8715,9 +9422,9 @@ } }, "wordwrap": { - "version": "0.0.3", - "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "version": "1.0.0", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, "wrap-ansi": { @@ -8757,6 +9464,15 @@ "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/write/-/write-1.0.3.tgz", + "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://botbuilder.myget.org/F/aitemplates/npm/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package.json b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package.json index d985fc9d92..13db3b4959 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package.json +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/package.json @@ -10,8 +10,8 @@ "copy-templates": "copyfiles --up 1 \"./src/**/*.json\" \"./lib\"", "prebuild": "npm run lint", "build": "tsc --p tsconfig.json && npm run copy-templates", - "lint": "tslint -t vso ./src/**/*.ts", - "lint-fix": "tslint --fix ./src/**/*.ts", + "lint": "eslint ./src/**/*.ts", + "lint-fix": "eslint --fix ./src/**/*.ts", "start": "npm run build && node ./lib/index.js NODE_ENV=development", "watch": "nodemon ./lib/index.js NODE_ENV=development", "test": "mocha", @@ -38,7 +38,11 @@ "@types/i18next-node-fs-backend": "^0.0.30", "@types/node": "^10.10.1", "@types/restify": "^7.2.4", + "@typescript-eslint/eslint-plugin": "^1.10.2", + "@typescript-eslint/eslint-plugin-tslint": "^1.10.2", + "@typescript-eslint/parser": "^1.10.2", "copyfiles": "^2.1.0", + "eslint": "^5.16.0", "nock": "^10.0.6", "mocha": "^6.1.4", "mocha-junit-reporter": "^1.22.0", @@ -47,7 +51,7 @@ "replace": "^1.0.0", "rimraf": "^2.6.2", "tslint": "^5.12.1", - "tslint-microsoft-contrib": "6.0.0", + "tslint-microsoft-contrib": "^6.0.0", "typescript": "^3.2.2" }, "env": { diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/defaultAdapter.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/defaultAdapter.ts index fca85dbecb..0acd44eaee 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/defaultAdapter.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/defaultAdapter.ts @@ -21,7 +21,7 @@ import { import { IBotSettings } from '../services/botSettings'; export class DefaultAdapter extends BotFrameworkAdapter { - constructor( + public constructor( settings: Partial, adapterSettings: Partial, userState: UserState, diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/sampleSkillAdapter.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/sampleSkillAdapter.ts index e27a06404b..ef5a135dd5 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/sampleSkillAdapter.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/adapters/sampleSkillAdapter.ts @@ -24,7 +24,7 @@ import { IBotSettings } from '../services/botSettings'; export class SampleSkillAdapter extends SkillHttpBotAdapter { - constructor( + public constructor( settings: Partial, userState: UserState, conversationState: ConversationState, diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/bots/dialogBot.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/bots/dialogBot.ts index a360c6e1f8..caf63831b9 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/bots/dialogBot.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/bots/dialogBot.ts @@ -14,19 +14,19 @@ import { Dialog, DialogContext, DialogSet, - DialogState, - DialogTurnResult } from 'botbuilder-dialogs'; + DialogState } from 'botbuilder-dialogs'; export class DialogBot extends ActivityHandler { private readonly telemetryClient: BotTelemetryClient; private readonly solutionName: string = 'sampleSkill'; private readonly rootDialogId: string; - private dialogs: DialogSet; + private readonly dialogs: DialogSet; - constructor( + public constructor( conversationState: ConversationState, telemetryClient: BotTelemetryClient, - dialog: T) { + dialog: T + ) { super(); this.rootDialogId = dialog.id; @@ -36,7 +36,7 @@ export class DialogBot extends ActivityHandler { this.onTurn(this.turn.bind(this)); } - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config public async turn(turnContext: TurnContext, next: () => Promise): Promise { // Client notifying this bot took to long to respond (timed out) if (turnContext.activity.code === EndOfConversationCodes.BotTimedOut) { @@ -51,7 +51,7 @@ export class DialogBot extends ActivityHandler { const dc: DialogContext = await this.dialogs.createContext(turnContext); if (dc.activeDialog !== undefined) { - const result: DialogTurnResult = await dc.continueDialog(); + await dc.continueDialog(); } else { await dc.beginDialog(this.rootDialogId); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/mainDialog.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/mainDialog.ts index 8a600df787..f2d83bb8fa 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/mainDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/mainDialog.ts @@ -50,7 +50,7 @@ export class MainDialog extends RouterDialog { private readonly contextAccessor: StatePropertyAccessor; // Constructor - constructor( + public constructor( settings: Partial, services: BotServices, responseManager: ResponseManager, @@ -74,7 +74,6 @@ export class MainDialog extends RouterDialog { } protected async onStart(dc: DialogContext): Promise { - const locale: string = i18next.language; await dc.context.sendActivity(this.responseManager.getResponse(MainResponses.welcomeMessage)); } @@ -138,8 +137,6 @@ export class MainDialog extends RouterDialog { protected async onEvent(dc: DialogContext): Promise { switch (dc.context.activity.name) { case Events.skillBeginEvent: { - // tslint:disable-next-line: no-any - const state: any = await this.stateAccessor.get(dc.context); const userData: Map = >dc.context.activity.value; if (userData === undefined) { throw new Error('userData is not an instance of Map'); @@ -236,7 +233,7 @@ export class MainDialog extends RouterDialog { // Sign out user // PENDING check adapter.getTokenStatusAsync const tokens: TokenStatus[] = []; - tokens.forEach(async (token: TokenStatus) => { + tokens.forEach(async (token: TokenStatus): Promise => { if (token.connectionName !== undefined) { await adapter.signOutUser(dc.context, token.connectionName); } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/sampleDialog.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/sampleDialog.ts index aa69a965c5..8a5923cfce 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/sampleDialog.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/sampleDialog.ts @@ -27,7 +27,7 @@ export class SampleDialog extends SkillDialogBase { private readonly nameKey: string = 'name'; // Constructor - constructor( + public constructor( settings: Partial, services: BotServices, responseManager: ResponseManager, @@ -66,7 +66,7 @@ export class SampleDialog extends SkillDialogBase { const tokens: Map = new Map(); tokens.set(this.nameKey, sc.result); - //tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const response: any = this.responseManager.getResponse(SampleResponses.haveNameMessage, tokens); // tslint:disable-next-line: no-unsafe-any await sc.context.sendActivity(response); diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/skillDialogBase.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/skillDialogBase.ts index fac5f42402..63a1fb39d6 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/skillDialogBase.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/dialogs/skillDialogBase.ts @@ -30,10 +30,6 @@ import { SharedResponses } from '../responses/shared/sharedResponses'; import { BotServices} from '../services/botServices'; import { IBotSettings } from '../services/botSettings'; -enum DialogIds { - skillModeAuth = 'SkillAuth' -} - export class SkillDialogBase extends ComponentDialog { private readonly solutionName: string = 'sampleSkill'; protected settings: Partial; @@ -41,13 +37,14 @@ export class SkillDialogBase extends ComponentDialog { protected stateAccessor: StatePropertyAccessor; protected responseManager: ResponseManager; - constructor( + public constructor( dialogId: string, settings: Partial, services: BotServices, responseManager: ResponseManager, stateAccessor: StatePropertyAccessor, - telemetryClient: BotTelemetryClient) { + telemetryClient: BotTelemetryClient + ) { super(dialogId); this.services = services; this.responseManager = responseManager; @@ -97,9 +94,9 @@ export class SkillDialogBase extends ComponentDialog { const providerTokenResponse: IProviderTokenResponse | undefined = sc.result; if (providerTokenResponse !== undefined) { - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const state: any = await this.stateAccessor.get(sc.context); - // tslint:disable-next-line: no-unsafe-any + // tslint:disable-next-line: no-any no-unsafe-any state.token = providerTokenResponse.tokenResponse.token; } @@ -175,7 +172,7 @@ export class SkillDialogBase extends ComponentDialog { await sc.context.sendActivity(this.responseManager.getResponse(SharedResponses.errorMessage)); // clear state - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config const state: any = await this.stateAccessor.get(sc.context); // tslint:disable-next-line: no-unsafe-any state.clear(); diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/index.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/index.ts index 9e515545d0..d726543182 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/index.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/index.ts @@ -19,18 +19,15 @@ import { Dialog, DialogState } from 'botbuilder-dialogs'; import { - IAuthenticationConnection, - ISkillManifest, manifestGenerator, SkillContext, SkillHttpAdapter } from 'botbuilder-skills'; import { ICognitiveModelConfiguration, - IOAuthConnection, Locales, - MultiProviderAuthDialog, ResponseManager} from 'botbuilder-solutions'; import i18next from 'i18next'; +// tslint:disable-next-line: match-default-export-name import i18nextNodeFsBackend from 'i18next-node-fs-backend'; import { join } from 'path'; import * as restify from 'restify'; @@ -49,19 +46,20 @@ import { BotServices } from './services/botServices'; import { IBotSettings } from './services/botSettings'; // Configure internationalization and default locale +// tslint:disable-next-line: no-floating-promises i18next.use(i18nextNodeFsBackend) -.init({ - fallbackLng: 'en', - preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ] -}) -.then(async () => { - await Locales.addResourcesFromPath(i18next, 'common'); -}); + .init({ + fallbackLng: 'en', + preload: [ 'de', 'en', 'es', 'fr', 'it', 'zh' ] + }) + .then(async (): Promise => { + await Locales.addResourcesFromPath(i18next, 'common'); + }); const cognitiveModels: Map = new Map(); const cognitiveModelDictionary: { [key: string]: Object } = cognitiveModelsRaw.cognitiveModels; const cognitiveModelMap: Map = new Map(Object.entries(cognitiveModelDictionary)); -cognitiveModelMap.forEach((value: Object, key: string) => { +cognitiveModelMap.forEach((value: Object, key: string): void => { cognitiveModels.set(key, value); }); @@ -79,7 +77,7 @@ if (botSettings.appInsights === undefined) { } function getTelemetryClient(settings: Partial): BotTelemetryClient { - if (settings && settings.appInsights && settings.appInsights.instrumentationKey) { + if (settings !== undefined && settings.appInsights !== undefined && settings.appInsights.instrumentationKey !== undefined) { const instrumentationKey: string = settings.appInsights.instrumentationKey; return new ApplicationInsightsTelemetryClient(instrumentationKey); @@ -166,6 +164,7 @@ const server: restify.Server = restify.createServer(); // Enable the Application Insights middleware, which helps correlate all activity // based on the incoming request. server.use(restify.plugins.bodyParser()); +// tslint:disable-next-line:no-unsafe-any server.use(ApplicationInsightsWebserverMiddleware); server.listen(process.env.port || process.env.PORT || '3980', (): void => { @@ -178,18 +177,18 @@ server.listen(process.env.port || process.env.PORT || '3980', (): void => { }); // Listen for incoming requests -server.post('/api/messages', (req: restify.Request, res: restify.Response) => { +server.post('/api/messages', async (req: restify.Request, res: restify.Response): Promise => { // Route received a request to adapter for processing - botAdapter.processActivity(req, res, async (turnContext: TurnContext) => { + await botAdapter.processActivity(req, res, async (turnContext: TurnContext): Promise => { // route to bot activity handler. await bot.run(turnContext); }); }); // Listen for incoming assistant requests -server.post('/api/skill/messages', (req: restify.Request, res: restify.Response) => { +server.post('/api/skill/messages', async (req: restify.Request, res: restify.Response): Promise => { // Route received a request to adapter for processing - adapter.processActivity(req, res, async (turnContext: TurnContext) => { + await adapter.processActivity(req, res, async (turnContext: TurnContext): Promise => { // route to bot activity handler. await bot.run(turnContext); }); @@ -198,24 +197,3 @@ server.post('/api/skill/messages', (req: restify.Request, res: restify.Response) const manifestPath: string = join(__dirname, 'manifestTemplate.json'); server.use(restify.plugins.queryParser()); server.get('/api/skill/manifest', manifestGenerator(manifestPath, botSettings)); - -// This method creates a MultiProviderAuthDialog based on a skill manifest. -function buildAuthDialog(skill: ISkillManifest, settings: Partial): MultiProviderAuthDialog|undefined { - if (skill.authenticationConnections !== undefined && skill.authenticationConnections.length > 0) { - if (settings.oauthConnections !== undefined) { - const oauthConnections: IOAuthConnection[] | undefined = settings.oauthConnections.filter( - (oauthConnection: IOAuthConnection) => { - return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection) => { - return authenticationConnection.serviceProviderId === oauthConnection.provider; - }); - }); - if (oauthConnections !== undefined) { - return new MultiProviderAuthDialog(oauthConnections); - } - } else { - throw new Error(`You must configure at least one supported OAuth connection to use this skill: ${skill.name}.`); - } - } - - return undefined; -} diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/main/mainResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/main/mainResponses.ts index 0170823dfa..85cf31432a 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/main/mainResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/main/mainResponses.ts @@ -15,9 +15,9 @@ export class MainResponses implements IResponseIdCollection { public static pathToResource?: string = join(__dirname, 'resources'); public static readonly welcomeMessage: string = 'WelcomeMessage'; public static readonly helpMessage: string = 'HelpMessage'; - public static readonly greetingMessage : string = 'GreetingMessage'; - public static readonly goodbyeMessage : string = 'GoodbyeMessage'; - public static readonly logOut : string = 'LogOut'; - public static readonly featureNotAvailable : string = 'FeatureNotAvailable'; + public static readonly greetingMessage: string = 'GreetingMessage'; + public static readonly goodbyeMessage: string = 'GoodbyeMessage'; + public static readonly logOut: string = 'LogOut'; + public static readonly featureNotAvailable: string = 'FeatureNotAvailable'; public static readonly cancelMessage: string = 'CancelMessage'; } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/sample/sampleResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/sample/sampleResponses.ts index 8cf8a3a179..9fcb699222 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/sample/sampleResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/sample/sampleResponses.ts @@ -13,6 +13,6 @@ export class SampleResponses implements IResponseIdCollection { // Generated accessors public name: string = SampleResponses.name; public static pathToResource?: string = join(__dirname, 'resources'); - public static readonly namePrompt : string = 'NamePrompt'; - public static readonly haveNameMessage : string = 'HaveNameMessage'; + public static readonly namePrompt: string = 'NamePrompt'; + public static readonly haveNameMessage: string = 'HaveNameMessage'; } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/shared/sharedResponses.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/shared/sharedResponses.ts index 3c2732a0d2..38dcc00b50 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/shared/sharedResponses.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/responses/shared/sharedResponses.ts @@ -13,10 +13,10 @@ export class SharedResponses implements IResponseIdCollection { // Generated accessors public name: string = SharedResponses.name; public static pathToResource?: string = join(__dirname, 'resources'); - public static readonly didntUnderstandMessage : string = 'DidntUnderstandMessage'; - public static readonly cancellingMessage : string = 'CancellingMessage'; - public static readonly noAuth : string = 'NoAuth'; - public static readonly authFailed : string = 'AuthFailed'; - public static readonly actionEnded : string = 'ActionEnded'; - public static readonly errorMessage : string = 'ErrorMessage'; + public static readonly didntUnderstandMessage: string = 'DidntUnderstandMessage'; + public static readonly cancellingMessage: string = 'CancellingMessage'; + public static readonly noAuth: string = 'NoAuth'; + public static readonly authFailed: string = 'AuthFailed'; + public static readonly actionEnded: string = 'ActionEnded'; + public static readonly errorMessage: string = 'ErrorMessage'; } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botServices.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botServices.ts index e3aa65e756..368e6c301e 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botServices.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botServices.ts @@ -15,7 +15,7 @@ export class BotServices { public cognitiveModelSets: Map> = new Map(); - constructor(settings: Partial, telemetryClient: BotTelemetryClient) { + public constructor(settings: Partial, telemetryClient: BotTelemetryClient) { const luisPredictionOptions: LuisPredictionOptions = { telemetryClient: telemetryClient, logPersonalInformation: true @@ -24,14 +24,14 @@ export class BotServices { try { if (settings.cognitiveModels !== undefined) { - settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string) => { + settings.cognitiveModels.forEach((value: ICognitiveModelConfiguration, key: string): void => { const language: string = key; const config: ICognitiveModelConfiguration = value; const cognitiveModelSet: Partial = { luisServices: new Map() }; - config.languageModels.forEach((model: LuisService) => { + config.languageModels.forEach((model: LuisService): void => { const luisService: LuisService = new LuisService(model); const luisApp: LuisApplication = { applicationId: luisService.appId, @@ -47,7 +47,7 @@ export class BotServices { }); } } catch (err) { - throw new Error(err); + throw err; } } } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botSettings.ts b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botSettings.ts index 5f951f6bf7..8068cbe30a 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botSettings.ts +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/src/services/botSettings.ts @@ -4,7 +4,7 @@ */ import { IBotSettingsBase } from 'botbuilder-solutions'; -// tslint:disable-next-line: no-empty-interface +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/tslint/config export interface IBotSettings extends IBotSettingsBase { } diff --git a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/tslint.json b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/tslint.json index a177ef07ec..91c8a37d7d 100644 --- a/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/tslint.json +++ b/templates/Virtual-Assistant-Template/typescript/samples/sample-skill/tslint.json @@ -1,26 +1,42 @@ { - "defaultSeverity": "error", - "extends": [ - "tslint:recommended", - "tslint-microsoft-contrib" - ], - "linterOptions":{ - "exclude": [ - "src/dialogs/shared/resources/*" - ] - }, - "rules": { - "function-name": [ true, - { - "static-method-regex":"^[a-z][\\w\\d]+$" - } - ], - "linebreak-style": [false], - "member-ordering": [false], - "no-relative-imports": [false], - "completed-docs": [false] - }, - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" + "defaultSeverity": "error", + "extends": [ + "tslint:recommended", + "tslint-microsoft-contrib" + ], + "linterOptions": { + "exclude": [ + "src/dialogs/shared/resources/*", + "src/services/DispatchLuis.ts" ] - } \ No newline at end of file + }, + "rules": { + "function-name": [ + true, + { + "static-method-regex": "^[a-z][\\w\\d]+$" + } + ], + "strict-boolean-expressions": [ + true, + "allow-undefined-union", + "allow-null-union", + "allow-mix", + "allow-string", + "ignore-rhs" + ], + "linebreak-style": false, + "completed-docs": false, + "no-relative-imports": false, + "export-name": false, + "member-ordering": false, + "no-use-before-declare": false, + "no-function-constructor-with-string-args": false, + "no-reserved-keywords": false, + "no-increment-decrement": false, + "no-unnecessary-bind": false + }, + "rulesDirectory": [ + "tslint-microsoft-contrib" + ] +} \ No newline at end of file diff --git a/yaml/csharp/README.md b/yaml/csharp/README.md index ce1534829e..2bd99149b3 100644 --- a/yaml/csharp/README.md +++ b/yaml/csharp/README.md @@ -59,6 +59,9 @@ trigger: include: - 'templates/Virtual-Assistant-Template/csharp/Sample/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 demands: @@ -109,6 +112,16 @@ steps: summaryFileLocation: '$(Build.SourcesDirectory)\templates\Virtual-Assistant-Template\csharp\Sample\VirtualAssistantSample.Tests\coverage.cobertura.xml' reportDirectory: '$(Build.SourcesDirectory)\templates\Virtual-Assistant-Template\csharp\Sample\VirtualAssistantSample.Tests' ``` +By default, the *Pipeline* automatically triggers a build for each new pull-request. This *Pipeline's* behavior can be disabled using the following configuration: +``` +pr: none +``` +In case that you want to activate this, you can use the following configuration: +``` +pr: +- master +``` + ## Configure build step by step in Pipelines 1. With the `YAML` file configurated you can go to *Azure DevOps* site and proceed to add the new Pipeline. Selecting the *Pipelines* option, will appear the builds like the following screenshot: diff --git a/yaml/csharp/botbuilder-skills.yml b/yaml/csharp/botbuilder-skills.yml index 873006d70d..9d19a277b4 100644 --- a/yaml/csharp/botbuilder-skills.yml +++ b/yaml/csharp/botbuilder-skills.yml @@ -9,6 +9,9 @@ trigger: include: - 'lib/csharp/microsoft.bot.builder.skills/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 demands: diff --git a/yaml/csharp/botbuilder-solutions.yml b/yaml/csharp/botbuilder-solutions.yml index a2e6d05ae1..e94c77b77c 100644 --- a/yaml/csharp/botbuilder-solutions.yml +++ b/yaml/csharp/botbuilder-solutions.yml @@ -9,6 +9,9 @@ trigger: include: - 'lib/csharp/microsoft.bot.builder.solutions/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 demands: diff --git a/yaml/csharp/virtual-assistant-sample.yml b/yaml/csharp/virtual-assistant-sample.yml index d8631e1c73..a113633881 100644 --- a/yaml/csharp/virtual-assistant-sample.yml +++ b/yaml/csharp/virtual-assistant-sample.yml @@ -9,6 +9,9 @@ trigger: include: - 'templates/Virtual-Assistant-Template/csharp/Sample/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 demands: diff --git a/yaml/typescript/README.md b/yaml/typescript/README.md index d4d14a1e7c..43f07a788f 100644 --- a/yaml/typescript/README.md +++ b/yaml/typescript/README.md @@ -27,6 +27,7 @@ A personalized *Pipeline* in *Azure DevOps* usign a `YAML` file. In first place, you need to create a `YAML` file with the configuration that the *Pipeline* will use. This is according to the needs of the user. This is an example to configure the `YAML` file. You are able to create or add this file in the root of your project or in any location, this doesn't affect or change the functionality of the `YAML`. + ``` # specific branch build trigger: @@ -39,6 +40,9 @@ trigger: include: - 'templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 steps: @@ -83,6 +87,17 @@ steps: summaryFileLocation: 'templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/coverage/cobertura-coverage.xml' reportDirectory: 'templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/coverage/' ``` + +By default, the *Pipeline* automatically triggers a buid for each new pull-request. This *Pipeline's* behavior can be disabled using the following configuration: +``` +pr: none +``` +In case that you want to activate this, you can use the following configuration: +``` +pr: +- master +``` + ## Configure build step by step in Pipelines 1. With the `YAML` file configurated you can go to *Azure DevOps* site and proceed to add the new Pipeline. Selecting the *Pipelines* option, will appear the builds like the following screenshot: diff --git a/yaml/typescript/botbuilder-skills.yml b/yaml/typescript/botbuilder-skills.yml index aa08399a04..0d29d2bec0 100644 --- a/yaml/typescript/botbuilder-skills.yml +++ b/yaml/typescript/botbuilder-skills.yml @@ -8,6 +8,9 @@ trigger: paths: include: - 'lib/typescript/botbuilder-skills/*' + +# By default will disable PR builds +pr: none pool: vmImage: 'vs2017-win2016' diff --git a/yaml/typescript/botbuilder-solutions.yml b/yaml/typescript/botbuilder-solutions.yml index 22cea7b3c0..a55a779d4e 100644 --- a/yaml/typescript/botbuilder-solutions.yml +++ b/yaml/typescript/botbuilder-solutions.yml @@ -9,6 +9,9 @@ trigger: include: - 'lib/typescript/botbuilder-solutions/*' +# By default will disable PR builds +pr: none + pool: vmImage: 'vs2017-win2016' steps: diff --git a/yaml/typescript/botskills.yml b/yaml/typescript/botskills.yml index b3ff4d4dbf..2a34f22e52 100644 --- a/yaml/typescript/botskills.yml +++ b/yaml/typescript/botskills.yml @@ -9,12 +9,14 @@ trigger: include: - lib/typescript/botskills/* +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 demands: - npm - npm - steps: - task: Npm@1 displayName: 'npm install' diff --git a/yaml/typescript/generator-botbuilder-assistant.yml b/yaml/typescript/generator-botbuilder-assistant.yml index a99d1441b5..9a62252f59 100644 --- a/yaml/typescript/generator-botbuilder-assistant.yml +++ b/yaml/typescript/generator-botbuilder-assistant.yml @@ -9,6 +9,9 @@ trigger: include: - 'templates/Virtual-Assistant-Template/typescript/generator-botbuilder-assistant/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 steps: diff --git a/yaml/typescript/sample-assistant.yml b/yaml/typescript/sample-assistant.yml index 9164adb95e..1cafff7874 100644 --- a/yaml/typescript/sample-assistant.yml +++ b/yaml/typescript/sample-assistant.yml @@ -9,6 +9,9 @@ trigger: include: - 'templates/Virtual-Assistant-Template/typescript/samples/sample-assistant/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 steps: diff --git a/yaml/typescript/sample-skill.yml b/yaml/typescript/sample-skill.yml index 5c913a00e7..47ae84c3a0 100644 --- a/yaml/typescript/sample-skill.yml +++ b/yaml/typescript/sample-skill.yml @@ -9,10 +9,12 @@ trigger: include: - 'templates/Virtual-Assistant-Template/typescript/samples/sample-skill/*' +# By default will disable PR builds +pr: none + pool: name: Hosted VS2017 demands: npm - steps: - task: NodeTool@0 displayName: 'Use Node 10.x'