From 8f86aa769eb775c836f9fad194661fa9e59691a8 Mon Sep 17 00:00:00 2001 From: John Reilly Date: Mon, 28 Aug 2023 19:20:52 +0100 Subject: [PATCH] feat: open ai generated descriptions (#656) * feat: open ai generated descriptions * feat: do updates * feat: more descriptions * feat: more descriptions * feat: more descriptions * fix: booboo * fix: ' * feat: more descriptions * feat: more descriptions * feat: more descriptions * feat: more descriptions * feat: more descriptions * feat: more descriptions * fix: capitalisation --- .gitignore | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../blog/2012-02-23-joy-of-json/index.md | 1 + .../index.md | 1 + .../index.md | 9 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 7 +- .../2012-10-22-mvc-3-meet-dictionary/index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../2013-05-04-how-im-using-cassette/index.md | 5 +- .../index.md | 3 +- .../index.md | 3 +- .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 27 ++--- .../index.md | 1 + .../index.md | 1 + .../index.md | 13 ++- .../index.md | 1 + .../index.md | 13 ++- .../index.md | 1 + .../index.md | 15 +-- .../index.md | 25 ++-- .../index.md | 1 + .../index.md | 1 + .../index.md | 49 ++++---- .../index.md | 1 + .../blog/2014-12-05-whats-in-a-name/index.md | 1 + .../index.md | 7 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 15 +-- .../index.md | 1 + .../2015-03-20-partialview-tostring/index.md | 1 + .../index.md | 1 + .../index.md | 11 +- .../index.md | 1 + .../index.md | 11 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 13 ++- .../index.md | 13 ++- .../2015-09-10-things-done-changed/index.md | 1 + .../index.md | 17 +-- .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 26 +++-- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 5 +- .../2016-10-05-react-component-curry/index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 16 ++- .../index.md | 1 + .../index.md | 3 +- .../blog/2017-02-01-hands-free-https/index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../2017-03-30-im-looking-for-work/index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 7 +- .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 6 +- .../index.md | 3 +- .../index.md | 9 +- .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../blog/2018-06-16-vsts-yaml-up/index.md | 1 + .../index.md | 1 + .../2018-07-09-cypress-and-auth0/index.md | 7 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../2018-10-27-making-a-programmer/index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 5 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 13 ++- .../blog/2020-04-04-up-to-clouds/index.md | 1 + .../index.md | 5 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 15 +-- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 31 ++--- .../index.md | 3 +- .../index.md | 5 +- .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 9 +- .../index.md | 18 +-- .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 25 ++-- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../2021-04-10-hello-world-bicep/index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 9 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 9 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 3 +- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 5 +- .../index.md | 21 ++-- .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 1 + .../index.md | 2 +- open-ai-description/bun.lockb | Bin 0 -> 41278 bytes open-ai-description/index.ts | 97 ++++++++++++++++ open-ai-description/package.json | 18 +++ open-ai-description/sample.env | 3 + open-ai-description/summarizer.ts | 109 ++++++++++++++++++ open-ai-description/tsconfig.json | 107 +++++++++++++++++ trim-xml/bun.lockb | Bin 3734 -> 4222 bytes trim-xml/tsconfig.json | 2 +- 252 files changed, 848 insertions(+), 251 deletions(-) create mode 100755 open-ai-description/bun.lockb create mode 100644 open-ai-description/index.ts create mode 100644 open-ai-description/package.json create mode 100644 open-ai-description/sample.env create mode 100644 open-ai-description/summarizer.ts create mode 100644 open-ai-description/tsconfig.json diff --git a/.gitignore b/.gitignore index 4bf599805d4..1df8913216e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules img.sh devto.sh -APIClientGenerator \ No newline at end of file +APIClientGenerator +.env \ No newline at end of file diff --git a/blog-website/blog/2012-01-07-standing-on-shoulders-of-giants/index.md b/blog-website/blog/2012-01-07-standing-on-shoulders-of-giants/index.md index 7516f316d5f..8ae84574ff3 100644 --- a/blog-website/blog/2012-01-07-standing-on-shoulders-of-giants/index.md +++ b/blog-website/blog/2012-01-07-standing-on-shoulders-of-giants/index.md @@ -3,6 +3,7 @@ slug: standing-on-shoulders-of-giants title: 'Standing on the Shoulders of Giants...' authors: johnnyreilly hide_table_of_contents: false +description: 'John starts a blog inspired by Scott Hanselman to share useful tools and techniques for web development.' --- It started with Scott Hanselman. I had no particular plans to start a blog at all. However, I was reading Scott Hanselman's turn of the year [post](http://www.hanselman.com/blog/YourBlogIsTheEngineOfCommunity.aspx) and I was struck with an idea. diff --git a/blog-website/blog/2012-01-14-jqgrid-its-just-far-better-grid/index.md b/blog-website/blog/2012-01-14-jqgrid-its-just-far-better-grid/index.md index 0c330e757c9..207c63dfbf9 100644 --- a/blog-website/blog/2012-01-14-jqgrid-its-just-far-better-grid/index.md +++ b/blog-website/blog/2012-01-14-jqgrid-its-just-far-better-grid/index.md @@ -4,6 +4,7 @@ title: "jqGrid - it's just a far better grid" authors: johnnyreilly tags: [jqgrid, ajax, jquery] hide_table_of_contents: false +description: 'jqGrid is a sleek & efficient grid component for ASP.NET projects. Its minimal data exchange between client and server impressed John no end.' --- The year was 2010 (not really that long ago I know) and the project that I was working on was sorely in need of a new grid component. It was an [ASP.NET WebForms](http://www.asp.net/web-forms) project and for some time we'd been using what was essentially a glorified [datagrid](http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.datagrid.aspx) which had a few extra features implemented to allow us to change column order / columns displayed / copy contents to clipboard etc. Our grid worked perfectly fine - it gave us the functionality we needed. However, it looked pretty terrible, and had some "quirky" approaches in place for supporting IE and Firefox side by side. Also, at the time we were attempting to make our app seem new and exciting again for the users. The surprising truth is that users seem to be more impressed with a visual revamp than with new or amended functionality. So I was looking for something which would make them sit up and say "oooh - isn't it pretty!". Unfortunately the nature of the organisation I was working for was not one that lended itself to paying for components. They were occasionally willing to do that but the hoops that would have to be jumped through first, the forms that would need to be signed in triplicate by people that had nearly nothing to do with the project made that an unattractive prospect. So I began my search initially looking at the various open source offerings that were around. As a minimum I was looking for something that would do what our home-grown component did already (change column order / columns displayed / copy contents to clipboard etc) but hopefully in a "nicer" way. Also, I had long been unhappy with the fact that to get our current grid to render results we did a \***full postback**\* to the server and re-rendered the whole page. Pointless! Why should you need to do all this each time when you only wanted to refresh the data? Instead I was thinking about using an [Ajax](http://en.wikipedia.org/wiki/Ajax_%28programming%29) approach; a grid that could just get the data that it needed and render it to the client. This seemed to me a vastly "cleaner" solution - why update a whole screen when you only want to update a small part of it? Why not save yourself the trouble of having to ensure that all other screen controls are persisted just as you'd like them after the postback? I also thought it was probably something that would scale better as it would massively reduce the amount of data moving backwards and forwards between client and server. No need for a full page life cycle on the server each time the grid refreshes. Just simple data travelling down the pipes of web. With the above criteria in mind I set out on my Google quest for a grid. Quite soon I found that there was a component out there which seemed to do all that I wanted and far more besides. It was called [jqGrid](http://www.trirand.com/blog/): diff --git a/blog-website/blog/2012-01-24-what-on-earth-is-jquery-and-why-should/index.md b/blog-website/blog/2012-01-24-what-on-earth-is-jquery-and-why-should/index.md index 2a85e328f0b..e5db399341f 100644 --- a/blog-website/blog/2012-01-24-what-on-earth-is-jquery-and-why-should/index.md +++ b/blog-website/blog/2012-01-24-what-on-earth-is-jquery-and-why-should/index.md @@ -4,6 +4,7 @@ title: 'What on earth is jQuery? And why should I care?' authors: johnnyreilly tags: [jqgrid, ajax, jquery] hide_table_of_contents: false +description: 'What is jQuery? Discover the truth about the JavaScript library thats taking the web development world by storm - its simply brilliant!' --- What on earth is jQuery? What's a jQuery plugin? diff --git a/blog-website/blog/2012-01-30-javascript-getting-to-know-beast/index.md b/blog-website/blog/2012-01-30-javascript-getting-to-know-beast/index.md index e2e7c110ece..eb5292a5e2c 100644 --- a/blog-website/blog/2012-01-30-javascript-getting-to-know-beast/index.md +++ b/blog-website/blog/2012-01-30-javascript-getting-to-know-beast/index.md @@ -4,9 +4,10 @@ title: 'JavaScript - getting to know the beast...' authors: johnnyreilly tags: [javascript, c#] hide_table_of_contents: false +description: 'Discovering jQuery and advice from Elijah Manor and Douglas Crockford changes Johns initial dislike of JavaScripts quirks.' --- -So it's 2010 and I've started using jQuery. jQuery is a JavaScript library. This means that I'm writing JavaScript... Gulp! I should say that at this point in time I \***hated**\* JavaScript (I have mentioned this previously). But what I know now is that I barely understood the language at all. All the JavaScript I knew was the result of copying and pasting after I'd hit "view source". I don't feel too bad about this - not because my ignorance was laudable but because I certainly wasn't alone in this. It seems that up until recently hardly anyone knew anything about JavaScript. It puzzles me now that I thought this was okay. I suppose like many people I didn't think JavaScript was capable of much and hence felt time spent researching it would be wasted. Just to illustrate where I was then, here is 2009 John's idea of some pretty "advanced" JavaScript: +So it's 2010 and I've started using jQuery. jQuery is a JavaScript library. This means that I'm writing JavaScript... Gulp! I should say that at this point in time I **hated** JavaScript (I have mentioned this previously). But what I know now is that I barely understood the language at all. All the JavaScript I knew was the result of copying and pasting after I'd hit "view source". I don't feel too bad about this - not because my ignorance was laudable but because I certainly wasn't alone in this. It seems that up until recently hardly anyone knew anything about JavaScript. It puzzles me now that I thought this was okay. I suppose like many people I didn't think JavaScript was capable of much and hence felt time spent researching it would be wasted. Just to illustrate where I was then, here is 2009 John's idea of some pretty "advanced" JavaScript: diff --git a/blog-website/blog/2012-02-05-potted-history-of-using-ajax-on/index.md b/blog-website/blog/2012-02-05-potted-history-of-using-ajax-on/index.md index fe096a85ffa..589e5198e4b 100644 --- a/blog-website/blog/2012-02-05-potted-history-of-using-ajax-on/index.md +++ b/blog-website/blog/2012-02-05-potted-history-of-using-ajax-on/index.md @@ -4,6 +4,7 @@ title: 'A Potted History of using Ajax (on the Microsoft Stack of Love)' authors: johnnyreilly tags: [ajax, jquery, json, microsoft] hide_table_of_contents: false +description: 'Discovering Ajax and JSON transformed Johns approach to programming by lifting limitations and improving performance.' --- This post originally started out as an explanation of JSON. However as I wrote this quickly got abandoned in favour of writing about how I came to use JSON in the first place - which was through the use of Ajax. Having written a goodly amount I've now decided to move the actual JSON stuff into another post since I think Ajax is probably worth thinking about by itself rather than as an aside. So let me start at the beginning and explain how I came to use Ajax in the first place (this may take some time so please bear with me). In late 2004 I first started working on a project which I was to remain involved with (on and off) for a very long time indeed. The project was part financial reporting system and part sales incentivisation tool; it was used internally in the investment bank in which I was working. The project had been in existence for a number of years and had a web front end which at that point would been built in a combination of HTML, JavaScript, classic ASP and with a Visual Basic 6.0 back end. One of the reasons I had been brought on to the project was to help ".Net-ify" the thing and migrate it to ASP.NET and C#. I digress. The interesting thing about this app was that there were actually some quite advanced things being done with it (despite the classic ASP / VB). The users could enter trades into the system which represented actual trades that had been entered into a trading system elsewhere in the organisation. These trades would be assigned a reporting value which would be based on their various attributes. (Stay with me people this will get more interesting I \***promise**\*.) The calculation of the reporting value was quite an in depth process and needed to be performed server-side. However, the users had decreed that it wasn't acceptable to do a full postback to the server to perform this calculation; they wanted it done "on-the-fly". Now if you asked me at the time I'd have said "can't be done". Fortunately the other people working on the project then weren't nearly so defeatist. Instead they went away and found Microsoft's [webservice.htc](http://msdn.microsoft.com/en-us/library/ie/ms531033%28v=vs.85%29.aspx) library. For those of you that don't know this was a JavaScript library that Microsoft came up with to enable the access of Web Services on the client. Given that it was designed to work with IE 5 I suspect it was created between 1999-2001 (but I'm not certain about that). Now it came as a revelation to me but this was a JavaScript library that talked to our web services through the medium of XML. In short it was my first encounter with anything remotely [Ajax]()\-y. It was exciting! However, the possibilities of what we could do didn't actually become apparent to me for some years. It's worth saying that the way we were using webservice.htc was exceedingly simplistic and rather than investigating further I took the limited ways we were using it as indications of the limitations of Ajax and / or webservice.htc. So for a long time I thought the following: - The only way to pass multiple arguments to a web service was to package up arguments into a single string with delimiters which you could [split]() and unpackage as your first step on the server. diff --git a/blog-website/blog/2012-02-15-wcf-transport-windows-authentication/index.md b/blog-website/blog/2012-02-15-wcf-transport-windows-authentication/index.md index 10948b34712..f2356fa1798 100644 --- a/blog-website/blog/2012-02-15-wcf-transport-windows-authentication/index.md +++ b/blog-website/blog/2012-02-15-wcf-transport-windows-authentication/index.md @@ -4,6 +4,7 @@ title: 'WCF Transport Windows authentication using NetTcpBinding in an Intranet authors: johnnyreilly tags: [WCF, Authentication] hide_table_of_contents: false +description: 'John explains authentication issues when migrating from .NET Remoting to WCF. The post highlights a security feature and suggests solutions.' --- ## Update diff --git a/blog-website/blog/2012-02-23-joy-of-json/index.md b/blog-website/blog/2012-02-23-joy-of-json/index.md index e7b9c86b181..3497be29184 100644 --- a/blog-website/blog/2012-02-23-joy-of-json/index.md +++ b/blog-website/blog/2012-02-23-joy-of-json/index.md @@ -4,6 +4,7 @@ title: 'The Joy of JSON' authors: johnnyreilly tags: [json] hide_table_of_contents: false +description: 'JSON is a lightweight data format that helps create and read JavaScript objects. This article traces its discovery and explains its usefulness.' --- So back to JSON. For those of you that don't know JSON stands for JavaScript Object Notation and is lightweight text based data interchange format. Rather than quote other people verbatim you can find thorough explanations of JSON here: - [Introducing JSON](http://www.json.org/) diff --git a/blog-website/blog/2012-03-03-jquery-unobtrusive-remote-validation/index.md b/blog-website/blog/2012-03-03-jquery-unobtrusive-remote-validation/index.md index d7488e5d6a5..e3f589d1023 100644 --- a/blog-website/blog/2012-03-03-jquery-unobtrusive-remote-validation/index.md +++ b/blog-website/blog/2012-03-03-jquery-unobtrusive-remote-validation/index.md @@ -4,6 +4,7 @@ title: 'jQuery Unobtrusive Remote Validation' authors: johnnyreilly tags: [jquery, jquery validation, jquery unobtrusive validation] hide_table_of_contents: false +description: 'Learn how to do remote validation with unobtrusive data attributes in ASP.NET MVC. Block validation and re-evaluate it with this hacky solution.' --- Just recently I have been particularly needing to make use of remote / server-side validation in my ASP.NET MVC application and found that the unobtrusive way of using this seemed to be rather inadequately documented (of course it's possible that it's well documented and I just didn't find the resources). Anyway I've rambled on much longer than I intended to in this post so here's the TL;DR: diff --git a/blog-website/blog/2012-03-12-striving-for-javascript-convention/index.md b/blog-website/blog/2012-03-12-striving-for-javascript-convention/index.md index 3dfe2e48fd1..919fb49c588 100644 --- a/blog-website/blog/2012-03-12-striving-for-javascript-convention/index.md +++ b/blog-website/blog/2012-03-12-striving-for-javascript-convention/index.md @@ -4,13 +4,16 @@ title: 'Striving for (JavaScript) Convention' authors: johnnyreilly tags: [javascript] hide_table_of_contents: false +description: 'Visual Studio 11 beta resolved issues. John has moved away from Hungarian Notation but retained using "$" as a prefix for jQuery objects.' --- ## Update +The speed of change makes fools of us all. Since I originally wrote this post all of 3 weeks ago Visual Studio 11 beta has been released and the issues I was seeking to solve have pretty much been resolved by the new innovations found therein. It's nicely detailed in [@carlbergenhem](http://www.twitter.com/carlbergenhem)'s blog post: [My Top 5 Visual Studio 11 Designer Improvements for ASP.NET 4.5 Development](https://blogs.telerik.com/blogs/posts/12-03-26/my-top-5-visual-studio-11-designer-improvements-for-asp-net-4-5-development.aspx). I've left the post in place below but much of what I said (particularly with regard to Hungarian Notation) I've now moved away from. That was originally my intention anyway so that's no bad thing. The one HN artefact that I've held onto is using "$" as a prefix for jQuery objects. I think that still makes sense. I would have written my first line of JavaScript in probably 2000. It probably looked something like this: `alert('hello world')`. I know. Classy. As I've mentioned before it was around 2010 before I took JavaScript in any way seriously. Certainly it was then when I started to actively learn the language. Because up until this point I'd been studiously avoiding writing any JavaScript at all I'd never really given thought to forms and conventions. When I wrote any JavaScript I just used the same style and approaches as I used in my main development language (of C#). By and large I have been following the .net naming conventions which are ably explained by Pete Brown [here](http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices). Over time I have started to move away from this approach. Without a deliberate intention to do so I have found myself adopting a different style for my JavaScript code as compared with anything else I write. I wouldn't go so far as to say I'm completely happy with the style I'm currently using. But I find it more helpful than not and thought it might be worth talking about. It was really 2 things that started me down the road of "rolling my own" convention: dynamic typing and the lack of safety nets. Let's take each in turn.... + -The speed of change makes fools of us all. Since I originally wrote this post all of 3 weeks ago Visual Studio 11 beta has been released and the issues I was seeking to solve have pretty much been resolved by the new innovations found therein. It's nicely detailed in [@carlbergenhem](http://www.twitter.com/carlbergenhem)'s blog post: [My Top 5 Visual Studio 11 Designer Improvements for ASP.NET 4.5 Development](https://blogs.telerik.com/blogs/posts/12-03-26/my-top-5-visual-studio-11-designer-improvements-for-asp-net-4-5-development.aspx). I've left the post in place below but much of what I said (particularly with regard to Hungarian Notation) I've now moved away from. That was originally my intention anyway so that's no bad thing. The one HN artefact that I've held onto is using "$" as a prefix for jQuery objects. I think that still makes sense. I would have written my first line of JavaScript in probably 2000. It probably looked something like this: `alert('hello world')`. I know. Classy. As I've mentioned before it was around 2010 before I took JavaScript in any way seriously. Certainly it was then when I started to actively learn the language. Because up until this point I'd been studiously avoiding writing any JavaScript at all I'd never really given thought to forms and conventions. When I wrote any JavaScript I just used the same style and approaches as I used in my main development language (of C#). By and large I have been following the .net naming conventions which are ably explained by Pete Brown [here](http://10rem.net/articles/net-naming-conventions-and-programming-standards---best-practices). Over time I have started to move away from this approach. Without a deliberate intention to do so I have found myself adopting a different style for my JavaScript code as compared with anything else I write. I wouldn't go so far as to say I'm completely happy with the style I'm currently using. But I find it more helpful than not and thought it might be worth talking about. It was really 2 things that started me down the road of "rolling my own" convention: dynamic typing and the lack of safety nets. Let's take each in turn.... ### 1\. Dynamic typing +### 1\. Dynamic typing Having grown up (in a development sense) using compiled and strongly-typed languages I was used to the IDE making it pretty clear what was what through friendly tooltips and the like: @@ -110,7 +113,3 @@ I really rather like this approach and I'm thinking about starting to adopt it. Despite being quite used to writing unit tests for all my server-side code I have not yet fully embraced unit testing on the client. Partly I've been holding back because of the variety of JavaScript testing frameworks available. I wasn't sure which to start with. But given that it is so easy to introduce bugs into JavaScript I have come to the conclusion that it's better to have some tests in place rather than none. Time to embrace the new. ## Conclusion I've found using Hungarian Notation useful whilst working in JavaScript. Not everyone will feel the same and I think that's fair enough; within reason I think it's generally a good idea to go with what you find useful. However, I am giving genuine consideration to moving to the DOJO style and moving back to my more standard camel-cased variable names instead of Hungarian Notation. Particularly since I strive to keep my functions short with the view that ideally each should 1 thing well. Keep it simple etc... And so in a perfect world the situation of forgetting a variables purpose shouldn't really arise... I think once I've got up and running with JavaScript unit tests I may make that move. Hungarian Notation may have proved to be just a stop-gap measure until better techniques were employed... - -``` - -``` diff --git a/blog-website/blog/2012-03-17-using-pubsub-observer-pattern-to/index.md b/blog-website/blog/2012-03-17-using-pubsub-observer-pattern-to/index.md index 3c39dc361bb..0370c37a737 100644 --- a/blog-website/blog/2012-03-17-using-pubsub-observer-pattern-to/index.md +++ b/blog-website/blog/2012-03-17-using-pubsub-observer-pattern-to/index.md @@ -4,6 +4,7 @@ title: 'Using the PubSub / Observer pattern to emulate constructor chaining with authors: johnnyreilly tags: [javascript] hide_table_of_contents: false +description: 'Pass objects between JavaScript files using PubSub interface to achieve code reusability without global scope pollution. No prototypes needed.' --- Yes the title of this post is \***painfully**\* verbose. Sorry about that. Couple of questions for you: - Have you ever liked the way you can have base classes in C# which can then be inherited and subclassed in a different file / class diff --git a/blog-website/blog/2012-03-22-wcf-moving-from-config-to-code-simple/index.md b/blog-website/blog/2012-03-22-wcf-moving-from-config-to-code-simple/index.md index fc7974c439c..696fc9da953 100644 --- a/blog-website/blog/2012-03-22-wcf-moving-from-config-to-code-simple/index.md +++ b/blog-website/blog/2012-03-22-wcf-moving-from-config-to-code-simple/index.md @@ -4,6 +4,7 @@ title: 'WCF - moving from Config to Code, a simple WCF service harness (plus imp authors: johnnyreilly tags: [WCF, authorization] hide_table_of_contents: false +description: 'John describes his approach to developing a Windows Service-hosted WCF service/client harness, including locking down WCF authorization.' --- Last time I wrote about WCF I was getting up and running with [WCF Transport Windows authentication using NetTcpBinding in an Intranet environment](../2012-02-15-wcf-transport-windows-authentication/index.md). I ended up with a WCF service hosted in a Windows Service which did pretty much what the previous post name implies. diff --git a/blog-website/blog/2012-04-05-making-pdfs-from-html-in-c-using/index.md b/blog-website/blog/2012-04-05-making-pdfs-from-html-in-c-using/index.md index abae5886184..4c4580581f9 100644 --- a/blog-website/blog/2012-04-05-making-pdfs-from-html-in-c-using/index.md +++ b/blog-website/blog/2012-04-05-making-pdfs-from-html-in-c-using/index.md @@ -4,6 +4,7 @@ title: 'Making PDFs from HTML in C# using WKHTMLtoPDF' authors: johnnyreilly tags: [wkhtmltopdf, c#, pdf] hide_table_of_contents: false +description: 'Create PDF reports from HTML with WKHTMLtoPDF, an open source tool that renders web pages to PDF, using a simple wrapper class.' --- ## Updated 03/01/2013 diff --git a/blog-website/blog/2012-04-16-simple-technique-for-initialising/index.md b/blog-website/blog/2012-04-16-simple-technique-for-initialising/index.md index ac2a93e803d..5ae8a5aa984 100644 --- a/blog-website/blog/2012-04-16-simple-technique-for-initialising/index.md +++ b/blog-website/blog/2012-04-16-simple-technique-for-initialising/index.md @@ -4,6 +4,7 @@ title: 'A Simple Technique for Initialising Properties with Internal Setters for authors: johnnyreilly tags: [unit testing, MOQ] hide_table_of_contents: false +description: 'Refactoring a legacy app includes adding unit tests, but properties with internal setters pose a problem. John explores various approaches.' --- I was recently working with my colleagues on refactoring a legacy application. We didn't have an immense amount of time available for this but the plan was to try and improve what was there as much as possible. In its initial state the application had no unit tests in place at all and so the plan was to refactor the code base in such a way as to make testing it a realistic proposition. To that end the [domain layer](http://en.wikipedia.org/wiki/Domain_layer) was being heavily adjusted and the GUI was being migrated from WebForms to MVC 3. The intention was to build up a pretty solid collection of unit tests. However, as we were working on this we realised we had a problem with properties on our models with [`internal`]() setters... diff --git a/blog-website/blog/2012-04-23-jshint-customising-your-hurt-feelings/index.md b/blog-website/blog/2012-04-23-jshint-customising-your-hurt-feelings/index.md index e6910e6a463..564979b5a94 100644 --- a/blog-website/blog/2012-04-23-jshint-customising-your-hurt-feelings/index.md +++ b/blog-website/blog/2012-04-23-jshint-customising-your-hurt-feelings/index.md @@ -4,6 +4,7 @@ title: 'JSHint - Customising your hurt feelings' authors: johnnyreilly tags: [jslint, jshint, eslint] hide_table_of_contents: false +description: 'JSHint is a tool for evaluating JavaScript code quality. Its configurable, has an extension for Visual Studio and is better than JSLint.' --- As I've started making greater use of JavaScript to give a richer GUI experience the amount of JS in my ASP.NET apps has unsurprisingly ballooned. If I'm honest, I hadn't given much consideration to the code quality of my JavaScript in the past. However, if I was going to make increasing use of it (and given the way the web is going at the moment I'd say that's a given) I didn't think this was tenable position to maintain. A friend of mine works for [Coverity](http://www.coverity.com/) which is a company that provides tools for analysing code quality. I understand, from conversations with him, that their tools provide static analysis for compiled languages such as C++ / C# / Java etc. I was looking for something similar for JavaScript. Like many, I have read and loved [Douglas Crockford's "JavaScript: The Good Parts"](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742); it is by some margin the most useful and interesting software related book I have read.So I was aware that Crockford had come up with his own JavaScript code quality tool called [JSLint](http://www.jslint.com/). JSLint is quite striking when you first encounter it: diff --git a/blog-website/blog/2012-04-28-beg-steal-or-borrow-decent-javascript/index.md b/blog-website/blog/2012-04-28-beg-steal-or-borrow-decent-javascript/index.md index 1419fcfc0fe..88382e9af03 100644 --- a/blog-website/blog/2012-04-28-beg-steal-or-borrow-decent-javascript/index.md +++ b/blog-website/blog/2012-04-28-beg-steal-or-borrow-decent-javascript/index.md @@ -4,6 +4,7 @@ title: 'Beg, Steal or Borrow a Decent JavaScript DateTime Converter' authors: johnnyreilly tags: [javascript, Serialization, .NET] hide_table_of_contents: false +description: 'ASP.NETs JavaScriptSerializer class is improved through ISO 8601 and a custom converter for better DateTime serialisation.' --- I've so named this blog post because it shamelessly borrows from the fine work of others: Sebastian Markbåge and Nathan Vonnahme. Sebastian wrote a blog post documenting a good solution to the ASP.NET JavaScriptSerializer DateTime problem at the tail end of last year. However, his solution didn't get me 100% of the way there when I tried to use it because of a need to support IE 8 which lead me to use Nathan Vonnahme's ISO 8601 JavaScript Date parser. I thought it was worth documenting this, hence this post, but just so I'm clear; the hard work here was done by Sebastian Markbåge and Nathan Vonnahme and not me. Consider me just a curator in this case. The original blog posts that I am drawing upon can be found here: 1. [http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/](http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/) and here: 2. [http://n8v.enteuxis.org/2010/12/parsing-iso-8601-dates-in-javascript/](http://n8v.enteuxis.org/2010/12/parsing-iso-8601-dates-in-javascript/) diff --git a/blog-website/blog/2012-05-07-globalizejs-number-and-date/index.md b/blog-website/blog/2012-05-07-globalizejs-number-and-date/index.md index a788eb305e4..9dce0f60ee9 100644 --- a/blog-website/blog/2012-05-07-globalizejs-number-and-date/index.md +++ b/blog-website/blog/2012-05-07-globalizejs-number-and-date/index.md @@ -4,6 +4,7 @@ title: 'Globalize.js - number and date localisation made easy' authors: johnnyreilly tags: [javascript, ASP.NET AJAX, Globalization] hide_table_of_contents: false +description: 'Globalize.js is a JavaScript library allowing developers to format and parse numbers and dates in a culture specific fashion for better user experience.' --- I wanted to write about a JavaScript library which seems to have had very little attention so far. And that surprises me as it's diff --git a/blog-website/blog/2012-05-30-dad-didnt-buy-any-games/index.md b/blog-website/blog/2012-05-30-dad-didnt-buy-any-games/index.md index 12382913b3c..9a8d33f8aa6 100644 --- a/blog-website/blog/2012-05-30-dad-didnt-buy-any-games/index.md +++ b/blog-website/blog/2012-05-30-dad-didnt-buy-any-games/index.md @@ -4,6 +4,7 @@ title: "Dad Didn't Buy Any Games" authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'Growing up in the 80s, John didnt have a computer until his father gave him one but with no games, encouraging him to learn programming.' --- Inspired by [Hanselmans post on how he got started in programming](http://www.hanselman.com/blog/SheLetMeTakeTheComputerHomeHowDidYouGetStartedInComputersAndProgramming.aspx) I thought I'd shared my own tale about how it all began... I grew up the 80's just outside London. For those of you of a different vintage let me paint a picture. These were the days when "Personal Computers", as they were then styled, were taking the world by storm. Every house would be equipped with either a ZX Spectrum, a Commodore 64 or an Amstrad CPC. These were 8 bit computers which were generally plugged into the family television and spent a good portion of their time loading games like [Target: Renegade](http://en.wikipedia.org/wiki/Target:_Renegade) from an audio cassette. But not in our house; we didn't have a computer. I remember mournfully pedalling home from friends houses on a number of occasions, glum as I compared my lot with theirs. Whereas my friends would be spending their evenings gleefully battering their keyboards as they thrashed the life out of various end-of-level bosses I was reduced to \***wasting**\* my time reading. That's right Enid Blyton - you were second best in my head. Then one happy day (and it may have been a Christmas present although I'm not certain) our family became the proud possessors of an [Amstrad CPC 6128](http://en.wikipedia.org/wiki/Amstrad_CPC): diff --git a/blog-website/blog/2012-06-04-reasons-to-be-cheerful-why-now-is-good/index.md b/blog-website/blog/2012-06-04-reasons-to-be-cheerful-why-now-is-good/index.md index 7d48d8dea65..0ea3f469235 100644 --- a/blog-website/blog/2012-06-04-reasons-to-be-cheerful-why-now-is-good/index.md +++ b/blog-website/blog/2012-06-04-reasons-to-be-cheerful-why-now-is-good/index.md @@ -4,6 +4,7 @@ title: 'Reasons to be Cheerful (why now is a good time to be a dev)' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'Easy access to information via Google and the rise of JavaScript, as well as blogs, screencasts, and podcasts have made learning coding easier.' --- I've been a working as a developer in some way, shape or form for just over 10 years now. And it occurred to me the other day that I can't think of a better time to be a software developer than right now diff --git a/blog-website/blog/2012-07-01-how-im-structuring-my-javascript-in-web/index.md b/blog-website/blog/2012-07-01-how-im-structuring-my-javascript-in-web/index.md index 2de8ce17e61..76e277f63a5 100644 --- a/blog-website/blog/2012-07-01-how-im-structuring-my-javascript-in-web/index.md +++ b/blog-website/blog/2012-07-01-how-im-structuring-my-javascript-in-web/index.md @@ -4,6 +4,7 @@ title: 'Optimally Serving Up JavaScript' authors: johnnyreilly tags: [asp.net mvc, javascript, cassette] hide_table_of_contents: false +description: 'John describes his "JS second" approach to structuring JavaScript and using HtmlHelper to control the order of scripts in web apps for internal use.' --- I have occasionally done some server-side JavaScript with Rhino and Node.js but this is the exception rather than the rule. Like most folk at the moment, almost all the JavaScript I write is in a web context. diff --git a/blog-website/blog/2012-07-16-rendering-partial-view-to-string/index.md b/blog-website/blog/2012-07-16-rendering-partial-view-to-string/index.md index 2a499400331..ca093fffd0f 100644 --- a/blog-website/blog/2012-07-16-rendering-partial-view-to-string/index.md +++ b/blog-website/blog/2012-07-16-rendering-partial-view-to-string/index.md @@ -4,6 +4,7 @@ title: 'Rendering Partial View to a String' authors: johnnyreilly tags: [asp.net mvc] hide_table_of_contents: false +description: 'John solves a problem with Partial Views in ASP.NET MVC, allowing simplified code and multiple view nesting.' --- ## Well done that man! diff --git a/blog-website/blog/2012-08-06-jquery-unobtrusive-validation/index.md b/blog-website/blog/2012-08-06-jquery-unobtrusive-validation/index.md index 0d5e57876e0..a7e6d092094 100644 --- a/blog-website/blog/2012-08-06-jquery-unobtrusive-validation/index.md +++ b/blog-website/blog/2012-08-06-jquery-unobtrusive-validation/index.md @@ -4,6 +4,7 @@ title: 'jQuery Unobtrusive Validation (+ associated gotchas)' authors: johnnyreilly tags: [jquery unobtrusive validation] hide_table_of_contents: false +description: 'Implement unobtrusive jQuery validation in your MVC application using HTML 5 data attributes to simplify code maintenance and reduce mistakes.' --- I was recently working on a project which had client side validation manually set up which essentially duplicated the same logic on the server. Like many things this had started out small and grown and grown until it became arduos and tedious to maintain. diff --git a/blog-website/blog/2012-08-16-closedxml-real-sdk-for-excel/index.md b/blog-website/blog/2012-08-16-closedxml-real-sdk-for-excel/index.md index e24627988b0..f447063462e 100644 --- a/blog-website/blog/2012-08-16-closedxml-real-sdk-for-excel/index.md +++ b/blog-website/blog/2012-08-16-closedxml-real-sdk-for-excel/index.md @@ -4,6 +4,7 @@ title: 'ClosedXML - the real SDK for Excel' authors: johnnyreilly tags: [Open XML, Excel, ClosedXML] hide_table_of_contents: false +description: 'Closed XML simplifies Excel document creation for developers with its straightforward API, sitting on top of Open XML. A frustration-solver for many!' --- Simplicity appeals to me. It always has. Something that is simple is straightforward to comprehend and is consequently easy to use. It's clarity. diff --git a/blog-website/blog/2012-08-24-how-to-attribute-encode-partialview-in/index.md b/blog-website/blog/2012-08-24-how-to-attribute-encode-partialview-in/index.md index 1c714e1b789..f1c5945e5dc 100644 --- a/blog-website/blog/2012-08-24-how-to-attribute-encode-partialview-in/index.md +++ b/blog-website/blog/2012-08-24-how-to-attribute-encode-partialview-in/index.md @@ -4,6 +4,7 @@ title: 'How to attribute encode a PartialView in MVC (Razor)' authors: johnnyreilly tags: [asp.net mvc, razor] hide_table_of_contents: false +description: 'Find out how to attribute encode PartialView HTML in Razor/ASP.Net MVC with the HTML helper method `PartialAttributeEncoded`.' --- This post is plagiarism. But I'm plagiarising myself so I don't feel too bad. diff --git a/blog-website/blog/2012-09-06-globalize-and-jquery-validate/index.md b/blog-website/blog/2012-09-06-globalize-and-jquery-validate/index.md index d395396f29d..35372e4157c 100644 --- a/blog-website/blog/2012-09-06-globalize-and-jquery-validate/index.md +++ b/blog-website/blog/2012-09-06-globalize-and-jquery-validate/index.md @@ -4,6 +4,7 @@ title: 'Globalize and jQuery Validation' authors: johnnyreilly tags: [asp.net mvc, Globalize, jQuery Validation] hide_table_of_contents: false +description: 'A jQuery plugin has been replaced by Globalize and makes locale specific number and date formatting easy with Javascript; a tutorial on how to use it.' --- ## Updated 05/10/2015 diff --git a/blog-website/blog/2012-09-24-giving-odata-to-crm-40/index.md b/blog-website/blog/2012-09-24-giving-odata-to-crm-40/index.md index 59aecad4e6c..33e86c7898f 100644 --- a/blog-website/blog/2012-09-24-giving-odata-to-crm-40/index.md +++ b/blog-website/blog/2012-09-24-giving-odata-to-crm-40/index.md @@ -4,6 +4,7 @@ title: 'Giving OData to CRM 4.0' authors: johnnyreilly tags: [OData, WCF, CRM, LINQ] hide_table_of_contents: false +description: 'The article explains how to create an OData service to access Dynamics CRM 4.0 by using LINQ to CRM provider and WCF Data Services.' --- Just recently I was tasked with seeing if we could provide a way to access our Dynamics CRM instance via OData. My initial investigations made it seem like there was nothing for me to do; [CRM 2011 provides OData support out of the box](http://msdn.microsoft.com/en-us/library/gg309461.aspx). Small problem. We were running CRM 4.0. diff --git a/blog-website/blog/2012-10-03-unit-testing-and-entity-framework-filth/index.md b/blog-website/blog/2012-10-03-unit-testing-and-entity-framework-filth/index.md index 9816726475d..d83e082dc6a 100644 --- a/blog-website/blog/2012-10-03-unit-testing-and-entity-framework-filth/index.md +++ b/blog-website/blog/2012-10-03-unit-testing-and-entity-framework-filth/index.md @@ -4,6 +4,7 @@ title: 'Unit Testing and Entity Framework: The Filth and the Fury' authors: johnnyreilly tags: [unit testing, Entity Framework, MOQ] hide_table_of_contents: false +description: 'Controversy arises over Unit Testing with Entity Framework & MOQ. A simple class could be used to wrap all Entity Framework code.' --- Just recently I've noticed that there appears to be something of a controversy around Unit Testing and Entity Framework. I first came across it as I was Googling around for useful posts on using MOQ in conjunction with EF. I've started to notice the topic more and more and as I have mixed feelings on the subject (that is to say I don't have a settled opinion) I thought I'd write about this and see if I came to any kind of conclusion... diff --git a/blog-website/blog/2012-10-05-using-web-optimization-with-mvc-3/index.md b/blog-website/blog/2012-10-05-using-web-optimization-with-mvc-3/index.md index 08a0f7e6d27..d85017057e5 100644 --- a/blog-website/blog/2012-10-05-using-web-optimization-with-mvc-3/index.md +++ b/blog-website/blog/2012-10-05-using-web-optimization-with-mvc-3/index.md @@ -4,6 +4,7 @@ title: 'Using Web Optimization with MVC 3' authors: johnnyreilly tags: [asp.net] hide_table_of_contents: false +description: 'Optimize JavaScript/CSS in MVC 3 through Microsofts NuGet package, bundling jQuery, jQuery UI, jQuery Validate and Modernizr.' --- A while ago I [wrote](http://icanmakethiswork.blogspot.com/2012/06/how-im-structuring-my-javascript-in-web.html#WebOptimization) about optimally serving up JavaScript in web applications. I mentioned that Microsoft had come up with a NuGet package called [Microsoft ASP.NET Web Optimization](http://nuget.org/packages/Microsoft.AspNet.Web.Optimization) which could help with that by minifying and bundling CSS and JavaScript. At the time I was wondering if I would be able to to use this package with pre-existing MVC 3 projects (given that the package had been released together with MVC 4). Happily it turns out you can. But it's not quite as straightforward as I might have liked so I've documented how to get going with this here... @@ -131,7 +132,7 @@ Once you've done this you're ready to start using Web Optimization in your MVC 3 With a "vanilla" MVC 3 app the only use of CSS and JavaScript files is found in `_Layout.cshtml`. To switch over to using Web Optimization you should replace the existing `_Layout.cshtml` with this: (you'll see that the few differences that there are between the 2 are solely around the replacement of link / script tags with references to `Scripts` and `Styles` instead) ```html - + @ViewBag.Title @@ -168,7 +169,7 @@ Do note that in the above `Scripts.Render` call we're rendering out 3 bundles; j In your root web.config file make sure that the following tag is in place: `<compilation debug="true" targetFramework="4.0">`. Then run, the generated HTML should look something like this: ```html - + Home Page @@ -245,7 +246,7 @@ This demonstrates that when the application has debug set to true you see the fu Now go back to your root `web.config` file and chance the debug tag to false: `<compilation debug="false" targetFramework="4.0">`. This time when you run, the generated HTML should look something like this: ```html - + Home Page diff --git a/blog-website/blog/2012-10-22-mvc-3-meet-dictionary/index.md b/blog-website/blog/2012-10-22-mvc-3-meet-dictionary/index.md index 0717253c954..4bedbcecbc5 100644 --- a/blog-website/blog/2012-10-22-mvc-3-meet-dictionary/index.md +++ b/blog-website/blog/2012-10-22-mvc-3-meet-dictionary/index.md @@ -4,6 +4,7 @@ title: 'MVC 3 meet Dictionary' authors: johnnyreilly tags: [.NET Framework] hide_table_of_contents: false +description: 'MVC 3 has a Dictionary deserialization bug resolved in MVC 4. Workaround includes using JSON stringify and manual deserialization.' --- ## Documenting a JsonValueProviderFactory Gotcha diff --git a/blog-website/blog/2012-11-02-xsdxml-schema-generator-xsdexe-taking/index.md b/blog-website/blog/2012-11-02-xsdxml-schema-generator-xsdexe-taking/index.md index 37f7b8461d1..3969bf19733 100644 --- a/blog-website/blog/2012-11-02-xsdxml-schema-generator-xsdexe-taking/index.md +++ b/blog-website/blog/2012-11-02-xsdxml-schema-generator-xsdexe-taking/index.md @@ -4,6 +4,7 @@ title: 'XSD/XML Schema Generator + Xsd.exe:Taking the pain out of manual XML' authors: johnnyreilly tags: [XSD, LINQ to XML] hide_table_of_contents: false +description: 'Discover how to use XSD for validating XML and generating C# classes from XSD files, including an online tool to simplify the task.' --- ## Is it 2003 again?!? diff --git a/blog-website/blog/2012-11-13-a-nicer-net-api-for-bloombergs-open-api/index.md b/blog-website/blog/2012-11-13-a-nicer-net-api-for-bloombergs-open-api/index.md index 8125b360859..7f35913fe60 100644 --- a/blog-website/blog/2012-11-13-a-nicer-net-api-for-bloombergs-open-api/index.md +++ b/blog-website/blog/2012-11-13-a-nicer-net-api-for-bloombergs-open-api/index.md @@ -4,6 +4,7 @@ title: "Getting up to speed with Bloomberg's Open API..." authors: johnnyreilly tags: [.NET, c#, Bloomberg, Open API] hide_table_of_contents: false +description: 'John documents his experience investigating Bloombergs Open API. He includes a simple C# console application wrapper for the API.' --- A good portion of any devs life is usually spent playing with APIs. If you need to integrate some other system into the system you're working on (and it's rare to come upon a situation where this doesn't happen at some point) then it's API time. diff --git a/blog-website/blog/2013-01-03-html-to-pdf-using-wcf-service/index.md b/blog-website/blog/2013-01-03-html-to-pdf-using-wcf-service/index.md index 61765acda0a..c86847342bd 100644 --- a/blog-website/blog/2013-01-03-html-to-pdf-using-wcf-service/index.md +++ b/blog-website/blog/2013-01-03-html-to-pdf-using-wcf-service/index.md @@ -4,6 +4,7 @@ title: 'HTML to PDF using a WCF Service' authors: johnnyreilly tags: [wkhtmltopdf, WCF, pdf] hide_table_of_contents: false +description: 'This ASP.NET WCF service creates PDFs from HTML and is remotely fired with wkhtmltopdf, using `webHttpBinding` for simple service calls.' --- ## TL; DR - "Talk is cheap. Show me the code." diff --git a/blog-website/blog/2013-01-09-twitterbootstrapmvc4-meet-bootstrap/index.md b/blog-website/blog/2013-01-09-twitterbootstrapmvc4-meet-bootstrap/index.md index 6edf8f2739a..614ff538e13 100644 --- a/blog-website/blog/2013-01-09-twitterbootstrapmvc4-meet-bootstrap/index.md +++ b/blog-website/blog/2013-01-09-twitterbootstrapmvc4-meet-bootstrap/index.md @@ -4,6 +4,7 @@ title: 'Twitter.Bootstrap.MVC4 meet Bootstrap Datepicker' authors: johnnyreilly tags: [asp.net mvc, Bootstrap] hide_table_of_contents: false +description: 'Learn about responsive web design and how to incorporate Twitter Bootstrap and Bootstrap Datepicker into ASP.Net MVC projects in this beginner’s guide.' --- ## Updated 14/01/2013 diff --git a/blog-website/blog/2013-01-14-twitterbootstrapmvc4-meet-bootstrap_14/index.md b/blog-website/blog/2013-01-14-twitterbootstrapmvc4-meet-bootstrap_14/index.md index 8a71eb8482a..96ccf32fa0f 100644 --- a/blog-website/blog/2013-01-14-twitterbootstrapmvc4-meet-bootstrap_14/index.md +++ b/blog-website/blog/2013-01-14-twitterbootstrapmvc4-meet-bootstrap_14/index.md @@ -4,6 +4,7 @@ title: 'Twitter.Bootstrap.MVC4 meet Bootstrap Datepicker *and* get your Internat authors: johnnyreilly tags: [Globalization, Bootstrap] hide_table_of_contents: false +description: 'Learn how to internationalize ASP.NET web apps using Globalize and Bootstrap Datepicker in this developers comprehensive step by step guide.' --- [Last time](../2013-01-09-twitterbootstrapmvc4-meet-bootstrap/index.md) I wrote about marrying up Twitter.Bootstrap.MVC4 and Bootstrap Datepicker. It came together quite nicely but when I took a more in depth look at what I'd done I discovered a problem. The brief work on regionalisation / internationalisation / localisation / globalisation / whatever it's called this week... wasn't really working. We had problems with the validation. @@ -158,7 +159,7 @@ The code above creates a script bundle for each culture when the application sta `_BootstrapLayout.basic.cshtml` has been amended to make use of the new bundles and also to include a meta tag that will used to drive regionalisation: ```html - + diff --git a/blog-website/blog/2013-02-13-using-expressions-with-constructors/index.md b/blog-website/blog/2013-02-13-using-expressions-with-constructors/index.md index a888056edbb..493f06932b8 100644 --- a/blog-website/blog/2013-02-13-using-expressions-with-constructors/index.md +++ b/blog-website/blog/2013-02-13-using-expressions-with-constructors/index.md @@ -4,6 +4,7 @@ title: 'Using Expressions with Constructors' authors: johnnyreilly tags: [.NET] hide_table_of_contents: false +description: 'This article explains how John used LINQs expression to extend a validation class and automatically change the property name.' --- Every now and then you think "x should be easy" - and it isn't. I had one of those situations this morning. Something I thought would take 5 minutes had me still pondering 30 minutes later. I finally cracked it (with the help of a colleague - thanks Marc!) and I wanted to note down what I did since I'm sure to forget this. diff --git a/blog-website/blog/2013-02-18-unit-testing-mvc-controllers-mocking/index.md b/blog-website/blog/2013-02-18-unit-testing-mvc-controllers-mocking/index.md index 18db3947ec0..6f5433ed4a2 100644 --- a/blog-website/blog/2013-02-18-unit-testing-mvc-controllers-mocking/index.md +++ b/blog-website/blog/2013-02-18-unit-testing-mvc-controllers-mocking/index.md @@ -4,6 +4,7 @@ title: 'Unit testing MVC controllers / Mocking UrlHelper' authors: johnnyreilly tags: [asp.net] hide_table_of_contents: false +description: 'This article presents a solution for testing ASP.net MVC controllers, including how to test controllers using UrlHelper.' --- ## I have put a name to my pain... diff --git a/blog-website/blog/2013-03-03-unit-testing-modelstate/index.md b/blog-website/blog/2013-03-03-unit-testing-modelstate/index.md index 4519d122060..ea0171bf1b0 100644 --- a/blog-website/blog/2013-03-03-unit-testing-modelstate/index.md +++ b/blog-website/blog/2013-03-03-unit-testing-modelstate/index.md @@ -4,6 +4,7 @@ title: 'Unit testing ModelState' authors: johnnyreilly tags: [asp.net mvc, unit testing] hide_table_of_contents: false +description: 'Testing Model validation in ASP.NET MVC can be accomplished by making use of ModelStateTestController class which simulates the functional tests.' --- - Me: "It can't be done" diff --git a/blog-website/blog/2013-03-11-decimalmodelbinder-for-nullable-decimals/index.md b/blog-website/blog/2013-03-11-decimalmodelbinder-for-nullable-decimals/index.md index 26f21c4a28d..9e208124459 100644 --- a/blog-website/blog/2013-03-11-decimalmodelbinder-for-nullable-decimals/index.md +++ b/blog-website/blog/2013-03-11-decimalmodelbinder-for-nullable-decimals/index.md @@ -4,6 +4,7 @@ title: 'DecimalModelBinder for nullable Decimals' authors: johnnyreilly tags: [Globalization, .NET] hide_table_of_contents: false +description: 'John forgot that MVCs ModelBinding doesnt handle regionalised numbers well. Provides solution found on Phil Haacks post.' --- My memory appears to be a sieve. Twice in the last year I've forgotten that MVCs ModelBinding doesn't handle regionalised numbers terribly well. Each time I've thought "hmmmm.... best Google that" and lo and behold come upon this post on the issue by the fantastic Phil Haack: diff --git a/blog-website/blog/2013-04-01-death-to-compatibility-mode/index.md b/blog-website/blog/2013-04-01-death-to-compatibility-mode/index.md index 1de72f6a86f..5bc39fca75c 100644 --- a/blog-website/blog/2013-04-01-death-to-compatibility-mode/index.md +++ b/blog-website/blog/2013-04-01-death-to-compatibility-mode/index.md @@ -4,6 +4,7 @@ title: 'Death to compatibility mode' authors: johnnyreilly tags: [internet explorer] hide_table_of_contents: false +description: 'John discusses compatibility mode in Internet Explorer and suggests using custom HTTP headers or meta tags to prevent rendering and CSS issues.' --- For just over 10 years my bread and butter has been the development and maintenance of line of business apps. More particularly, web apps built on the Microsoft stack of love ([© Scott Hanselman](https://channel9.msdn.com/Events/MIX/MIX11/FRM02)). These sort of apps are typically accessed via the company intranet and since "bring your own device" is still a relatively new innovation these apps are invariably built for everyones favourite browser: Internet Explorer. As we all know, enterprises are generally not that speedy when it comes to upgrades. So we're basically talking IE 9 at best, but more often than not, IE 8. @@ -74,7 +75,7 @@ Obviously there's a whole raft of ways you could get this in, using `Application The final approach uses meta tags. And, in my experience it is the most quirky approach - it doesn't always seem to work. First up, what do we do? Well, in each page served we include the following meta tag like this: ```html - + diff --git a/blog-website/blog/2013-04-09-making-ie-10s-clear-field-x-button-and/index.md b/blog-website/blog/2013-04-09-making-ie-10s-clear-field-x-button-and/index.md index 58ee43b75fe..91528d703c8 100644 --- a/blog-website/blog/2013-04-09-making-ie-10s-clear-field-x-button-and/index.md +++ b/blog-website/blog/2013-04-09-making-ie-10s-clear-field-x-button-and/index.md @@ -4,6 +4,7 @@ title: "Making IE 10's clear field (X) button and jQuery UI autocomplete play ni authors: johnnyreilly tags: [jQuery UI] hide_table_of_contents: false +description: 'IE 10 installed w/o notice on Johns machine, causing issues with jQuery UI auto-complete loading gifs which have been resolved with a CSS fix.' --- This morning when I logged on I was surprised to discover IE 10 had been installed onto my machine. I hadn't taken any action to trigger this myself and so I’m assuming that this was part of the general Windows Update mechanism. I know [Microsoft had planned to push IE 10 out through this mechanism](http://technet.microsoft.com/en-us/ie/jj898508.aspx). diff --git a/blog-website/blog/2013-04-17-ie-10-install-torches-javascript/index.md b/blog-website/blog/2013-04-17-ie-10-install-torches-javascript/index.md index f1d3b03cc0d..f867b3f2904 100644 --- a/blog-website/blog/2013-04-17-ie-10-install-torches-javascript/index.md +++ b/blog-website/blog/2013-04-17-ie-10-install-torches-javascript/index.md @@ -4,6 +4,7 @@ title: 'IE 10 Install Torches JavaScript Debugging in Visual Studio 2012 Through authors: johnnyreilly tags: [Visual Studio, javascript, IE 10] hide_table_of_contents: false +description: 'Learn how to fix missing Script Documents when debugging JavaScript in Visual Studio 2012, likely caused by auto-updating from IE9 to IE10.' --- OK the title of this post is a little verbose. I've just wasted a morning of my life trying to discover what happened to my ability to debug JavaScript in Visual Studio 2012. If you don't want to experience the same pain then read on... diff --git a/blog-website/blog/2013-04-26-a-navigation-animation-for-your-users/index.md b/blog-website/blog/2013-04-26-a-navigation-animation-for-your-users/index.md index 7c381d98229..97d6380609b 100644 --- a/blog-website/blog/2013-04-26-a-navigation-animation-for-your-users/index.md +++ b/blog-website/blog/2013-04-26-a-navigation-animation-for-your-users/index.md @@ -4,6 +4,7 @@ title: 'A navigation animation (for your users delectation)' authors: johnnyreilly tags: [CSS] hide_table_of_contents: false +description: 'Adding a CSS animation or GIF can help users navigating an app in an iframe get visual feedback despite the lack of browser feedback tics.' --- ## The Vexation diff --git a/blog-website/blog/2013-05-04-how-im-using-cassette/index.md b/blog-website/blog/2013-05-04-how-im-using-cassette/index.md index 96b41951125..9858f2eae1a 100644 --- a/blog-website/blog/2013-05-04-how-im-using-cassette/index.md +++ b/blog-website/blog/2013-05-04-how-im-using-cassette/index.md @@ -4,6 +4,7 @@ title: "How I'm Using Cassette part 1:Getting Up and Running" authors: johnnyreilly tags: [asp.net mvc, cassette] hide_table_of_contents: false +description: 'Learn how to serve JavaScript assets efficiently in ASP.Net MVC with Cassette to avoid duplicate scripts and ensure speedy loading.' --- ## Backing into the light @@ -137,7 +138,7 @@ If you're more familiar with the workings of Web Optimization than Cassette then Now we've created our bundles let's get the project serving up CSS and JavaScript using Cassette. First the layout file. Take the `_Layout.cshtml` file from this: ```html - + @@ -191,7 +192,7 @@ To this: ```html @{ Bundles.Reference("~/bundles/css"); Bundles.Reference("~/bundles/head"); Bundles.Reference("~/bundles/core"); } - + diff --git a/blog-website/blog/2013-06-06-how-im-using-cassette-part-2/index.md b/blog-website/blog/2013-06-06-how-im-using-cassette-part-2/index.md index 6369ca3eb57..3833ea9ae3a 100644 --- a/blog-website/blog/2013-06-06-how-im-using-cassette-part-2/index.md +++ b/blog-website/blog/2013-06-06-how-im-using-cassette-part-2/index.md @@ -4,6 +4,7 @@ title: "How I'm Using Cassette part 2:Get Cassette to Serve Scripts in Dependenc authors: johnnyreilly tags: [RequireJS, cassette] hide_table_of_contents: false +description: 'Cassettes script dependency order feature is the most useful, managing script order manually is tedious. Use server-side or JavaScript asset references.' --- [Last time](../2013-05-04-how-im-using-cassette/index.md) I wrote about Cassette I was talking about how to generally get up and running. How to use Cassette within an ASP.Net MVC project. What I want to write about now is (in my eyes) the most useful feature of Cassette by a country mile. This is Cassettes ability to ensure scripts are served in dependency order. @@ -90,7 +91,7 @@ $(document).ready(function () { $body .html( '
' + - 'I made it all go away...
' + 'I made it all go away...', ) .fadeIn(); }); diff --git a/blog-website/blog/2013-06-26-jquery-validate-native-unobtrusive-validation/index.md b/blog-website/blog/2013-06-26-jquery-validate-native-unobtrusive-validation/index.md index 70d539e17e1..650b5330ed1 100644 --- a/blog-website/blog/2013-06-26-jquery-validate-native-unobtrusive-validation/index.md +++ b/blog-website/blog/2013-06-26-jquery-validate-native-unobtrusive-validation/index.md @@ -4,6 +4,7 @@ title: 'jQuery Validation - Native Unobtrusive Validation Support!' authors: johnnyreilly tags: [jQuery Validation] hide_table_of_contents: false +description: 'Use HTML5 data attributes with jQuery Validation to simplify code and achieve validation unobtrusively. Ideal for dynamically added DOM elements.' --- Did you know that jQuery Validation natively supports the use of [HTML 5 data attributes](http://ejohn.org/blog/html-5-data-attributes/) to drive validation unobtrusively? Neither did I - I haven't seen any documentation for it. However, I was reading the [jQuery Validation test suite](https://github.com/jzaefferer/jquery-validation/blob/master/test/index.html) and that's what I spotted being used in some of the tests. @@ -19,7 +20,7 @@ So when I realised that there was native alternative available I was delighted. Not particularly exciting? Not noticably different to any other jQuery Validate demo you've ever seen? Fair enough. Now look at the source: ```html - + diff --git a/blog-website/blog/2013-08-08-announcing-jquery-validation/index.md b/blog-website/blog/2013-08-08-announcing-jquery-validation/index.md index ab75461aab9..5a67916d7a6 100644 --- a/blog-website/blog/2013-08-08-announcing-jquery-validation/index.md +++ b/blog-website/blog/2013-08-08-announcing-jquery-validation/index.md @@ -4,6 +4,7 @@ title: 'Announcing jQuery Validation Unobtrusive Native...' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'jQuery Validation Unobtrusive Native bridges data attributes and jQuery Validations native support. The ASP.Net MVC HTML extension is available on GitHub.' --- I've been busy working on an open source project called **[jQuery Validation Unobtrusive Native](https://github.com/johnnyreilly/jQuery.Validation.Unobtrusive.Native)**. [To see it in action take a look here](https://johnnyreilly.github.io/jQuery.Validation.Unobtrusive.Native/). diff --git a/blog-website/blog/2013-08-17-using-bootstrap-tooltips-to-display/index.md b/blog-website/blog/2013-08-17-using-bootstrap-tooltips-to-display/index.md index e544d522397..80d6491b347 100644 --- a/blog-website/blog/2013-08-17-using-bootstrap-tooltips-to-display/index.md +++ b/blog-website/blog/2013-08-17-using-bootstrap-tooltips-to-display/index.md @@ -4,6 +4,7 @@ title: 'Using Bootstrap Tooltips to display jQuery Validation error messages' authors: johnnyreilly tags: [Tooltip, Bootstrap, jQuery Validation] hide_table_of_contents: false +description: 'Using tooltips can be a better approach than displaying validation messages next to the element being validated in jQuery Validation.' --- I love jQuery Validation. I was recently putting together a screen which had a lot of different bits of validation going on. And the default jQuery Validation approach of displaying the validation messages next to the element being validated wasn't working for me. That is to say, because of the amount of elements on the form, the appearance of validation messages was really making a mess of the presentation. So what to do? @@ -21,7 +22,7 @@ After a certain amount of fiddling I came up with a fairly solid mechanism for g Beautiful isn't it? Now look at the source: ```html - + diff --git a/blog-website/blog/2013-10-04-migrating-from-jquery.validate.unobtrusive.js-to-jQuery.Validation.Unobtrusive.Native/index.md b/blog-website/blog/2013-10-04-migrating-from-jquery.validate.unobtrusive.js-to-jQuery.Validation.Unobtrusive.Native/index.md index 52982ee39e2..68911ebf68e 100644 --- a/blog-website/blog/2013-10-04-migrating-from-jquery.validate.unobtrusive.js-to-jQuery.Validation.Unobtrusive.Native/index.md +++ b/blog-website/blog/2013-10-04-migrating-from-jquery.validate.unobtrusive.js-to-jQuery.Validation.Unobtrusive.Native/index.md @@ -4,6 +4,7 @@ title: 'Migrating from jquery.validate.unobtrusive.js to jQuery.Validation.Unobt authors: johnnyreilly tags: [jQuery Validation] hide_table_of_contents: false +description: 'Migrating from jquery.validation.unobtrusive.js to jQuery.Validation.Unobtrusive.Native is easy, with only minor tweaks to HTML and JS needed.' --- So, you're looking at [jQuery.Validation.Unobtrusive.Native](https://github.com/johnnyreilly/jQuery.Validation.Unobtrusive.Native). You're thinking to yourself "Yeah, I'd really like to use the native unobtrusive support in jQuery Validation. But I've already got this app which is using [jquery.validate.unobtrusive.js](https://www.nuget.org/packages/jQuery.Validation.Unobtrusive/) \- actually how easy is switching over?" Well I'm here to tell you that it's pretty straightforward - here's a walkthrough of how it might be done. diff --git a/blog-website/blog/2013-10-30-getting-typescript-compile-on-save-and-continous-integration-to-play-nice/index.md b/blog-website/blog/2013-10-30-getting-typescript-compile-on-save-and-continous-integration-to-play-nice/index.md index 8149b1480a9..4ab16466cdf 100644 --- a/blog-website/blog/2013-10-30-getting-typescript-compile-on-save-and-continous-integration-to-play-nice/index.md +++ b/blog-website/blog/2013-10-30-getting-typescript-compile-on-save-and-continous-integration-to-play-nice/index.md @@ -4,6 +4,7 @@ title: 'Getting TypeScript Compile-on-Save and Continuous Integration to play ni authors: johnnyreilly tags: [TFS, typescript] hide_table_of_contents: false +description: 'Learn how to compile TypeScript in Visual Studio without making TypeScript compilation part of the build process on the server.' --- Well sort of... Perhaps this post should more accurately called "How to get CI to ignore your TypeScript whilst Visual Studio still compiles it..." diff --git a/blog-website/blog/2013-11-04-typescript-dont-forget-build-action-for-implicit-referencing/index.md b/blog-website/blog/2013-11-04-typescript-dont-forget-build-action-for-implicit-referencing/index.md index 9cae44b7e94..f95532c24cd 100644 --- a/blog-website/blog/2013-11-04-typescript-dont-forget-build-action-for-implicit-referencing/index.md +++ b/blog-website/blog/2013-11-04-typescript-dont-forget-build-action-for-implicit-referencing/index.md @@ -4,6 +4,7 @@ title: "TypeScript: Don't forget Build Action for Implicit Referencing..." authors: johnnyreilly tags: [typescript, Definitely Typed, typescript, nuget] hide_table_of_contents: false +description: 'TypeScript files in Visual Studio now implicitly reference each other. This caused problems for some projects and its important to check file settings.' --- As part of the [known breaking changes between 0.9 and 0.9.1](https://typescript.codeplex.com/wikipage?title=Known%20breaking%20changes%20between%200.8%20and%200.9&referringTitle=Documentation) there was this subtle but significant switch: diff --git a/blog-website/blog/2013-11-26-rolling-your-own-confirm-mechanism/index.md b/blog-website/blog/2013-11-26-rolling-your-own-confirm-mechanism/index.md index cf266660bdc..812c3697236 100644 --- a/blog-website/blog/2013-11-26-rolling-your-own-confirm-mechanism/index.md +++ b/blog-website/blog/2013-11-26-rolling-your-own-confirm-mechanism/index.md @@ -4,6 +4,7 @@ title: 'Rolling your own confirm mechanism using Promises and jQuery UI' authors: johnnyreilly tags: [jQuery UI] hide_table_of_contents: false +description: 'Learn how to create a custom confirm dialog using jQuery UI’s dialog and promises. The custom dialog is more configurable than the default `window.confirm`.' --- We're here to talk about the [confirm](https://developer.mozilla.org/en-US/docs/Web/API/Window.confirm) dialog. Or, more specifically, how we can make our own confirm dialog. diff --git a/blog-website/blog/2013-12-04-simple-fading-in-and-out-using-css-transitions/index.md b/blog-website/blog/2013-12-04-simple-fading-in-and-out-using-css-transitions/index.md index 4b0ca962726..f921c0d6fec 100644 --- a/blog-website/blog/2013-12-04-simple-fading-in-and-out-using-css-transitions/index.md +++ b/blog-website/blog/2013-12-04-simple-fading-in-and-out-using-css-transitions/index.md @@ -4,6 +4,7 @@ title: 'Simple fading in and out using CSS transitions and classes' authors: johnnyreilly tags: [CSS] hide_table_of_contents: false +description: 'Learn to create a fade effect with CSS transitions for improved animation and battery life. Warning: display: none behaves differently than jQuery.' --- Caveat emptor folks... Let me start off by putting my hands up and saying I am no expert on CSS. And furthermore let me say that this blog post is essentially the distillation of a heady session of googling on the topic of CSS transitions. The credit for the technique detailed here belongs to many others, I'm just documenting it for my own benefit (and for anyone who stumbles upon this). @@ -84,7 +85,7 @@ $(document).on( if ($faded.hasClass('fadedOut')) { $faded.css('display', 'none'); } - } + }, ); ``` diff --git a/blog-website/blog/2013-12-13-nuget-and-webmatrix-how-to-install/index.md b/blog-website/blog/2013-12-13-nuget-and-webmatrix-how-to-install/index.md index c13a91c9aed..0301be95345 100644 --- a/blog-website/blog/2013-12-13-nuget-and-webmatrix-how-to-install/index.md +++ b/blog-website/blog/2013-12-13-nuget-and-webmatrix-how-to-install/index.md @@ -4,6 +4,7 @@ title: 'NuGet and WebMatrix: How to install a specific version of a package' authors: johnnyreilly tags: [jquery, NuGet] hide_table_of_contents: false +description: 'WebMatrix lacks NuGet command line, but users can still install a specific version manually by following the necessary steps - a bit of a challenge.' --- I've recently been experimenting with WebMatrix. If you haven't heard of it, WebMatrix is Microsoft's _["free, lightweight, cloud-connected web development tool"](http://www.microsoft.com/web/webmatrix/)_. All marketing aside, it's pretty cool. You can whip up a site in next to no time, it has source control, publishing abilities, intellisense. Much good stuff. And one thing it has, that I genuinely hadn't expected is [NuGet](https://www.nuget.org/). Brilliant! diff --git a/blog-website/blog/2014-01-09-upgrading-to-typescript-095-personal/index.md b/blog-website/blog/2014-01-09-upgrading-to-typescript-095-personal/index.md index baabbaa186b..cfd5ee13332 100644 --- a/blog-website/blog/2014-01-09-upgrading-to-typescript-095-personal/index.md +++ b/blog-website/blog/2014-01-09-upgrading-to-typescript-095-personal/index.md @@ -4,6 +4,7 @@ title: 'Upgrading to TypeScript 0.9.5 - A Personal Memoir' authors: johnnyreilly tags: [typescript] hide_table_of_contents: false +description: 'Upgrade to TypeScript 0.9.5 worth it despite Visual Studio issues. Declaration merging glitches resolved by interface-driven approach.' --- I recently made the step to upgrade from TypeScript 0.9.1.1 to 0.9.5. To my surprise this process was rather painful and certainly not an unalloyed pleasure. Since I'm now on the other side, so to speak, I thought I'd share my experience and cast back a rope bridge to those about to journey over the abyss. diff --git a/blog-website/blog/2014-01-24-integration-testing-with-entity/index.md b/blog-website/blog/2014-01-24-integration-testing-with-entity/index.md index c6c0f91d3df..bf35d44fb21 100644 --- a/blog-website/blog/2014-01-24-integration-testing-with-entity/index.md +++ b/blog-website/blog/2014-01-24-integration-testing-with-entity/index.md @@ -4,6 +4,7 @@ title: 'Integration Testing with Entity Framework and Snapshot Backups' authors: johnnyreilly tags: [Database Snapshots, Integration Testing, SQL Server] hide_table_of_contents: false +description: 'The article shows how to use SQL Servers snapshot backups for creating effective integration tests that dont affect production data.' --- I've written before about how unit testing [Entity Framework is a contentious and sometimes pointless activity](../2012-10-03-unit-testing-and-entity-framework-filth/index.md). The TL;DR is that LINQ-to-Objects != Linq-to-Entities and so if you want some useful tests around your data tier then integration tests that actually hit a database are what you want. diff --git a/blog-website/blog/2014-02-12-wpf-and-mystic-meg-or-playing/index.md b/blog-website/blog/2014-02-12-wpf-and-mystic-meg-or-playing/index.md index ec4a460032c..cfffda83a5b 100644 --- a/blog-website/blog/2014-02-12-wpf-and-mystic-meg-or-playing/index.md +++ b/blog-website/blog/2014-02-12-wpf-and-mystic-meg-or-playing/index.md @@ -4,6 +4,7 @@ title: 'WPF and Mystic Meg or Playing Futurologist' authors: johnnyreilly tags: [SPA] hide_table_of_contents: false +description: 'Native client apps will eventually be replaced by rich web apps/SPAs. WPF will become more niche, but wont die, predicts John.' --- Time for an unusual post. Most of what gets put down here is technical "how-to's". It's usually prompted by something I've been working on and serves, as much as anything else, as an aide-memoire. Not this time. diff --git a/blog-website/blog/2014-02-27-typescript-and-requirejs-keep-it-simple/index.md b/blog-website/blog/2014-02-27-typescript-and-requirejs-keep-it-simple/index.md index bb282071116..98b2ab6996b 100644 --- a/blog-website/blog/2014-02-27-typescript-and-requirejs-keep-it-simple/index.md +++ b/blog-website/blog/2014-02-27-typescript-and-requirejs-keep-it-simple/index.md @@ -4,6 +4,7 @@ title: 'TypeScript and RequireJS (Keep It Simple)' authors: johnnyreilly tags: [typescript] hide_table_of_contents: false +description: 'This article explains how to mix TypeScript and RequireJS, gives examples of the code changes needed, and shows how to create a demo.' --- I'm not the first to take a look at mixing TypeScript and RequireJS but I wanted to get it clear in my head. Also, I've always felt the best way to learn is to do. So here we go. I'm going to create a TypeScript and RequireJS demo based on [John Papa's "Keep It Simple RequireJS Demo"](https://github.com/johnpapa/kis-requirejs-demo/). @@ -15,7 +16,7 @@ So let's fire up Visual Studio 2013 and create a new ASP.NET Web Application cal Add a new HTML file to the root called “index.html” and base it on “index3.html” from [John Papa’s demo](https://github.com/johnpapa/kis-requirejs-demo/blob/master/ModularDemo/index3.html): ```html - + TypeScript with RequireJS diff --git a/blog-website/blog/2014-03-05-caching-and-cache-busting-with-requirejs/index.md b/blog-website/blog/2014-03-05-caching-and-cache-busting-with-requirejs/index.md index ed09e97230d..ce2a7a1ea85 100644 --- a/blog-website/blog/2014-03-05-caching-and-cache-busting-with-requirejs/index.md +++ b/blog-website/blog/2014-03-05-caching-and-cache-busting-with-requirejs/index.md @@ -4,6 +4,7 @@ title: 'Caching and cache-busting with RequireJS' authors: johnnyreilly tags: [asp.net, RequireJS, cache, caching] hide_table_of_contents: false +description: 'Learn how to use "urlArgs" in RequireJS to manage caching and offer a reusable solution for both development and production environments.' --- Having put together a demo of using TypeScript with RequireJS my attention turned quickly to caching. Or rather, IE forced me to think about caching. diff --git a/blog-website/blog/2014-03-11-knockout-globalize-valuenumber-binding/index.md b/blog-website/blog/2014-03-11-knockout-globalize-valuenumber-binding/index.md index f85d48159e4..85b0368bffc 100644 --- a/blog-website/blog/2014-03-11-knockout-globalize-valuenumber-binding/index.md +++ b/blog-website/blog/2014-03-11-knockout-globalize-valuenumber-binding/index.md @@ -4,6 +4,7 @@ title: 'Knockout + Globalize = valueNumber Binding Handler' authors: johnnyreilly tags: [Globalize, Knockout] hide_table_of_contents: false +description: 'Learn how to use Globalize and Knockout to create a "valueNumber" binding handler that makes numeric validation and localization easy.' --- I’ve long used [Globalize](https://github.com/jquery/globalize/) for my JavaScript number formatting / parsing needs. In a current project I’m using Knockout for the UI. When it came to data-binding numeric values none of the default binding handlers seemed appropriate. What I wanted was a binding handler that: @@ -24,7 +25,7 @@ ko.bindingHandlers.valueNumber = { valueAccessor, allBindingsAccessor, viewModel, - bindingContext + bindingContext, ) { /** * Adapted from the KO hasfocus handleElementFocusChange function diff --git a/blog-website/blog/2014-03-17-the-surprisingly-happy-tale-of-visual/index.md b/blog-website/blog/2014-03-17-the-surprisingly-happy-tale-of-visual/index.md index 30a45023673..26f1f124cf7 100644 --- a/blog-website/blog/2014-03-17-the-surprisingly-happy-tale-of-visual/index.md +++ b/blog-website/blog/2014-03-17-the-surprisingly-happy-tale-of-visual/index.md @@ -4,6 +4,7 @@ title: 'The Surprisingly Happy Tale of Visual Studio Online, Continous Integrati authors: johnnyreilly tags: [Jasmine, TFS, unit testing, javascript, Continuous Integration] hide_table_of_contents: false +description: 'John recounts his experience with JavaScript unit testing using Jasmine and Chutzpah for integration with Visual Studio and Team Foundation Service.' --- ## Going off piste diff --git a/blog-website/blog/2014-04-01-typescript-instance-methods/index.md b/blog-website/blog/2014-04-01-typescript-instance-methods/index.md index d62406b6d2d..92d4e1c3cf7 100644 --- a/blog-website/blog/2014-04-01-typescript-instance-methods/index.md +++ b/blog-website/blog/2014-04-01-typescript-instance-methods/index.md @@ -4,6 +4,7 @@ title: 'TypeScript this is what I want! (the unfortunate neglect of Instance Met authors: johnnyreilly tags: [typescript] hide_table_of_contents: false +description: 'TypeScripts "Instance Methods" feature solves the `this` keyword issues in classes, unlike prototype methods. It suggests using a combination of the two.' --- I was recently reading [Jeff Walker's blog post "Why TypeScript Isn't the Answer"](http://www.walkercoderanger.com/blog/2014/02/typescript-isnt-the-answer/). This is part of series in which Jeff goes through various compile-to-JavaScript technologies including TypeScript, CoffeeScript and Dart and explains his view of why he feels they don't quite hit the mark. diff --git a/blog-website/blog/2014-05-05-typescript-jsdoc-and-intellisense/index.md b/blog-website/blog/2014-05-05-typescript-jsdoc-and-intellisense/index.md index da46e69ba08..348aa11fffd 100644 --- a/blog-website/blog/2014-05-05-typescript-jsdoc-and-intellisense/index.md +++ b/blog-website/blog/2014-05-05-typescript-jsdoc-and-intellisense/index.md @@ -4,6 +4,7 @@ title: 'TypeScript, JSDoc and Intellisense' authors: johnnyreilly tags: [jquery, JSDoc, typescript] hide_table_of_contents: false +description: 'Transforming API documentation into JSDoc for TypeScript: author explains how he enriched popular `jquery.d.ts` file with comments.' --- ## Days of Yore diff --git a/blog-website/blog/2014-05-15-team-foundation-server-continuous-integration-and-javascript-unit-tests-in-unit-test-project/index.md b/blog-website/blog/2014-05-15-team-foundation-server-continuous-integration-and-javascript-unit-tests-in-unit-test-project/index.md index 16fa63fa2f8..b34476c8588 100644 --- a/blog-website/blog/2014-05-15-team-foundation-server-continuous-integration-and-javascript-unit-tests-in-unit-test-project/index.md +++ b/blog-website/blog/2014-05-15-team-foundation-server-continuous-integration-and-javascript-unit-tests-in-unit-test-project/index.md @@ -11,6 +11,7 @@ tags: Chutzpah, ] hide_table_of_contents: false +description: 'Learn how to run JavaScript tests on TFS/VSO by creating a separate unit test project to house tests, and installing Chutzpah on TFS/VSO.' --- Do you like to separate out your unit tests from the project you are testing? I imagine so. My own practice when creating a new project in Visual Studio is to create a separate unit test project alongside whose responsibility is to house unit tests for that new project. diff --git a/blog-website/blog/2014-06-01-migrating-from-angularjs-to-angularts/index.md b/blog-website/blog/2014-06-01-migrating-from-angularjs-to-angularts/index.md index c8e1f8cb298..c15e1bb4645 100644 --- a/blog-website/blog/2014-06-01-migrating-from-angularjs-to-angularts/index.md +++ b/blog-website/blog/2014-06-01-migrating-from-angularjs-to-angularts/index.md @@ -4,6 +4,7 @@ title: 'Migrating from AngularJS to AngularTS - a walkthrough' authors: johnnyreilly tags: [Jasmine, typescript, Unit tests, AngularJS] hide_table_of_contents: false +description: 'Learn how to migrate an AngularJS app from JavaScript to TypeScript in this walkthrough on a simple website/app for sending prayer requests.' --- It started with nuns. Don't all good stories start that way? One of my (many) aunts is a Poor Clare nun. At some point in the distant past I was cajoled into putting together a simple website for her convent. This post is a walkthrough of how to migrate from AngularJS using JavaScript to AngularJS using TypeScript. It just so happens that the AngularJS app in question is the one that belongs to my mother's sister's convent. @@ -169,7 +170,7 @@ angular.module('poorClaresApp.services').factory( determineSiteSection: determineSiteSection, }; }, - ] + ], ); ``` @@ -189,7 +190,7 @@ As with `siteSectionService` we need to create an interface to define what `pray interface IPrayerRequestService { sendPrayerRequest: ( email: string, - prayFor: string + prayFor: string, ) => ng.IPromise<{ success: boolean; text: string; @@ -219,7 +220,7 @@ angular.module('poorClaresApp.services').factory( sendPrayerRequest: sendPrayerRequest, }; }, - ] + ], ); ``` @@ -264,7 +265,7 @@ angular.module('poorClaresApp.controllers').controller( }); }; }, - ] + ], ); ``` @@ -282,7 +283,7 @@ module poorClaresApp.controllers { static $inject = ['$scope', 'prayerRequestService']; constructor( private $scope: ng.IScope, - private prayerRequestService: IPrayerRequestService + private prayerRequestService: IPrayerRequestService, ) {} message: { success: boolean; text: string }; @@ -345,7 +346,7 @@ angular.module('poorClaresApp.controllers').controller( 'siteSectionService', function ( $scope: INavControllerScope, - siteSectionService: ISiteSectionService + siteSectionService: ISiteSectionService, ) { $scope.isCollapsed = true; $scope.siteSection = siteSectionService.getSiteSection(); @@ -354,10 +355,10 @@ angular.module('poorClaresApp.controllers').controller( siteSectionService.getSiteSection, function (newValue, oldValue) { $scope.siteSection = newValue; - } + }, ); }, - ] + ], ); ``` @@ -378,7 +379,7 @@ module poorClaresApp.controllers { static $inject = ['$scope', 'siteSectionService']; constructor( private $scope: INavControllerScope, - private siteSectionService: ISiteSectionService + private siteSectionService: ISiteSectionService, ) { $scope.isCollapsed = true; $scope.siteSection = siteSectionService.getSiteSection(); @@ -387,7 +388,7 @@ module poorClaresApp.controllers { siteSectionService.getSiteSection, function (newValue, oldValue) { $scope.siteSection = newValue; - } + }, ); } } @@ -413,11 +414,11 @@ angular.module('poorClaresApp.controllers').controller( 'siteSectionService', function ( $location: ng.ILocationService, - siteSectionService: ISiteSectionService + siteSectionService: ISiteSectionService, ) { siteSectionService.determineSiteSection($location.path()); }, - ] + ], ); ``` @@ -431,7 +432,7 @@ module poorClaresApp.controllers { static $inject = ['$location', 'siteSectionService']; constructor( private $location: ng.ILocationService, - private siteSectionService: ISiteSectionService + private siteSectionService: ISiteSectionService, ) { siteSectionService.determineSiteSection($location.path()); } diff --git a/blog-website/blog/2014-06-20-dates-DataAnnotations-and-data-impedance-mismatch/index.md b/blog-website/blog/2014-06-20-dates-DataAnnotations-and-data-impedance-mismatch/index.md index 8404dda6527..0e3aae2754e 100644 --- a/blog-website/blog/2014-06-20-dates-DataAnnotations-and-data-impedance-mismatch/index.md +++ b/blog-website/blog/2014-06-20-dates-DataAnnotations-and-data-impedance-mismatch/index.md @@ -4,6 +4,7 @@ title: 'A folk story wherein we shall find dates, DataAnnotations & data impedan authors: johnnyreilly tags: [Date] hide_table_of_contents: false +description: 'This article offers developers an attribute-based solution to prevent datetime errors, ensuring that DateTime properties only include dates.' --- If you ever take a step back from what you're doing it can sometimes seem pretty abstract. Here's an example. I was looking at an issue in an app that I was supporting. The problem concerned a field which was to store a date value. Let's call it, for the sake of argument, `valuation_date`. (Clearly in reality the field name was entirely different... Probably.) This field was supposed to represent a specific date, like June 15th 2012 or 19th August 2014. To be clear, a date and \***not**\* in any way, a time. diff --git a/blog-website/blog/2014-07-03-hottowel-angular-meet-typescript/index.md b/blog-website/blog/2014-07-03-hottowel-angular-meet-typescript/index.md index a99a5612be4..9e7f266a6eb 100644 --- a/blog-website/blog/2014-07-03-hottowel-angular-meet-typescript/index.md +++ b/blog-website/blog/2014-07-03-hottowel-angular-meet-typescript/index.md @@ -4,6 +4,7 @@ title: 'HotTowel-Angular meet TypeScript' authors: johnnyreilly tags: [typescript, AngularJS] hide_table_of_contents: false +description: 'Johnny Reilly creates a bare-bones port of the Hot Towel Angular SPA Template to TypeScript in order to demonstrate the ease of transition.' --- I've recently ported John Papa's popular [Hot Towel Angular SPA Template](https://github.com/johnpapa/HotTowel-Angular) to TypeScript. Why? [Because it was there.](http://en.wikipedia.org/wiki/George_Mallory) diff --git a/blog-website/blog/2014-08-01-angularjs-meet-aspnet-server-validation/index.md b/blog-website/blog/2014-08-01-angularjs-meet-aspnet-server-validation/index.md index 91e06efd25d..edf57ae723c 100644 --- a/blog-website/blog/2014-08-01-angularjs-meet-aspnet-server-validation/index.md +++ b/blog-website/blog/2014-08-01-angularjs-meet-aspnet-server-validation/index.md @@ -4,6 +4,7 @@ title: 'AngularJS meet ASP.Net Server Validation' authors: johnnyreilly tags: [asp.net, typescript, AngularJS] hide_table_of_contents: false +description: 'Learn how to perform server-side validation in your AngularJS and ASP.Net project using a `serverError` directive and server response error messages.' --- So. You're using AngularJS to build your front end with ASP.Net running on the server side. You're a trustworthy dev - you know that validation on the client will only get you so far. You need to validate on the server. @@ -129,7 +130,7 @@ app.directive('serverError', [ safeWatch(function () { return ngModelController.$error.server; }), - showHideValidation + showHideValidation, ); function showHideValidation(serverError) { @@ -141,7 +142,7 @@ app.directive('serverError', [ var errorKey = scope.name; errorHtml = template.replace( /%error%/, - errorDictionary[errorKey] || 'Unknown error occurred...' + errorDictionary[errorKey] || 'Unknown error occurred...', ); } decorator.html(errorHtml); @@ -274,7 +275,7 @@ module controllers { private $routeParams: sageEditRouteParams, private $scope: sageEditScope, private common: common, - private datacontext: datacontext + private datacontext: datacontext, ) { this.errors = {}; this.log = common.logger.getLogFn(controllerId); @@ -315,7 +316,7 @@ module controllers { if (response.success) { this.sage = response.entity; this.logSuccess( - 'Saved ' + this.sage.name + ' [' + this.sage.id + ']' + 'Saved ' + this.sage.name + ' [' + this.sage.id + ']', ); this.$location.path('/sages/detail/' + this.sage.id); } else { @@ -324,7 +325,7 @@ module controllers { angular.forEach(response.errors, (errors, field) => { (this.$scope.form[field]).$setValidity( 'server', - false + false, ); this.errors[field] = errors.join(','); }); @@ -404,7 +405,7 @@ var controllers; if (response.success) { _this.sage = response.entity; _this.logSuccess( - 'Saved ' + _this.sage.name + ' [' + _this.sage.id + ']' + 'Saved ' + _this.sage.name + ' [' + _this.sage.id + ']', ); _this.$location.path('/sages/detail/' + _this.sage.id); diff --git a/blog-website/blog/2014-08-08-getting-more-RESTful-with-Web-API/index.md b/blog-website/blog/2014-08-08-getting-more-RESTful-with-Web-API/index.md index 94a2c3957c0..a7dbfc9fb3c 100644 --- a/blog-website/blog/2014-08-08-getting-more-RESTful-with-Web-API/index.md +++ b/blog-website/blog/2014-08-08-getting-more-RESTful-with-Web-API/index.md @@ -4,6 +4,7 @@ title: 'Getting more RESTful with Web API and IHttpActionResult' authors: johnnyreilly tags: [ASP.NET] hide_table_of_contents: false +description: 'Learn how to use HTTP status codes in Web API methods to return successful or failed requests without wrapping the outcomes.' --- Up until, well yesterday really, I tended to have my Web API action methods all returning [200](http://en.wikipedia.org/wiki/HTTP_200#2xx_Success)'s no matter what. Successful request? 200 for you sir! Some validation error in the model? 200 for you too ma'am - but I'll wrap up the validation errors and send them back too. Database error? 200 and and an error message. diff --git a/blog-website/blog/2014-08-12-my-unrequited-love-for-isolate-scope/index.md b/blog-website/blog/2014-08-12-my-unrequited-love-for-isolate-scope/index.md index a47455f2bc2..7f4a9d46a6d 100644 --- a/blog-website/blog/2014-08-12-my-unrequited-love-for-isolate-scope/index.md +++ b/blog-website/blog/2014-08-12-my-unrequited-love-for-isolate-scope/index.md @@ -4,6 +4,7 @@ title: 'My Unrequited Love for Isolate Scope' authors: johnnyreilly tags: [typescript, javascript, Bootstrap, AngularJS] hide_table_of_contents: false +description: 'A new version of the serverError directive is presented without isolated scope after discovering directives can only create one isolated scope.' --- [I wrote a little while ago about creating a directive to present server errors on the screen in an Angular application](../2014-08-01-angularjs-meet-aspnet-server-validation/index.md). In my own (not so humble opinion), it was really quite nice. I was particularly proud of my usage of isolate scope. However, pride comes before a fall. @@ -50,7 +51,7 @@ So ladies and gentlemen, let me present serverError 2.0 – this time without is scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, - ngModelController: ng.INgModelController + ngModelController: ng.INgModelController, ) { // Extract values from attributes (deliberately not using isolated scope) var errorKey: string = attrs['name']; // eg "sage.name" @@ -67,7 +68,7 @@ So ladies and gentlemen, let me present serverError 2.0 – this time without is // Watch ngModelController.$error.server & show/hide validation accordingly scope.$watch( safeWatch(() => ngModelController.$error.server), - showHideValidation + showHideValidation, ); function showHideValidation(serverError: boolean) { @@ -75,11 +76,11 @@ So ladies and gentlemen, let me present serverError 2.0 – this time without is var errorHtml = ''; if (serverError) { var errorDictionary: { [field: string]: string } = scope.$eval( - errorDictionaryExpression + errorDictionaryExpression, ); errorHtml = template.replace( /%error%/, - errorDictionary[errorKey] || 'Unknown error occurred...' + errorDictionary[errorKey] || 'Unknown error occurred...', ); } decorator.html(errorHtml); @@ -147,7 +148,7 @@ So ladies and gentlemen, let me present serverError 2.0 – this time without is safeWatch(function () { return ngModelController.$error.server; }), - showHideValidation + showHideValidation, ); function showHideValidation(serverError) { @@ -157,7 +158,7 @@ So ladies and gentlemen, let me present serverError 2.0 – this time without is var errorDictionary = scope.$eval(errorDictionaryExpression); errorHtml = template.replace( /%error%/, - errorDictionary[errorKey] || 'Unknown error occurred...' + errorDictionary[errorKey] || 'Unknown error occurred...', ); } decorator.html(errorHtml); diff --git a/blog-website/blog/2014-09-06-running-javascript-unit-tests-in-appveyor/index.md b/blog-website/blog/2014-09-06-running-javascript-unit-tests-in-appveyor/index.md index e6fedf175ba..2a123847e06 100644 --- a/blog-website/blog/2014-09-06-running-javascript-unit-tests-in-appveyor/index.md +++ b/blog-website/blog/2014-09-06-running-javascript-unit-tests-in-appveyor/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Jasmine, javascript, Unit tests, Continuous Integration, AppVeyor, Chutzpah] hide_table_of_contents: false +description: 'AppVeyor and Chutzpah were integrated to run C# and JavaScript unit tests in a single PowerShell script for CI purposes.' --- ## With a little help from Chutzpah... diff --git a/blog-website/blog/2014-09-10-unit-testing-angular-controller-with/index.md b/blog-website/blog/2014-09-10-unit-testing-angular-controller-with/index.md index 485c43f7920..c3a40f21368 100644 --- a/blog-website/blog/2014-09-10-unit-testing-angular-controller-with/index.md +++ b/blog-website/blog/2014-09-10-unit-testing-angular-controller-with/index.md @@ -4,6 +4,7 @@ title: 'Unit Testing an Angular Controller with Jasmine' authors: johnnyreilly tags: [Jasmine, unit tests, AngularJS] hide_table_of_contents: false +description: 'John shares how they wrote unit tests for an Angular controller in Proverb using Jasmine 2.0, with heavily annotated JavaScript tests.' --- Anyone who reads my blog will know that I have been long in the habit of writing unit tests for my C# code. I'm cool like that. However, it took me a while to get up and running writing unit tests for my JavaScript code. I finally [got there](../2014-03-17-the-surprisingly-happy-tale-of-visual/index.md) using a combination of Jasmine 2.0 and Chutzpah. (Jasmine being my test framework and Chutzpah being my test runner.) @@ -55,7 +56,7 @@ module controllers { private $location: ng.ILocationService, private $routeParams: sageDetailRouteParams, private common: common, - private datacontext: datacontext + private datacontext: datacontext, ) { this.sage = undefined; this.title = 'Sage Details'; @@ -179,7 +180,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { _$q_, _$location_, _common_, - _datacontext_ + _datacontext_, ) { // Note how each parameter is prefixed and suffixed with "_" - this an Angular nicety // which allows you to have variables in your tests with the original reference name. @@ -204,7 +205,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { // this allows us to #1 detect that getById has been called // and #2 resolve / reject our promise as our test requires using getById_deferred spyOn(datacontext.sage, 'getById').and.returnValue( - getById_deferred.promise + getById_deferred.promise, ); // set up a spy on common.activateController and set it to call through @@ -214,7 +215,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { // set up spys on common.logger.getLogFn and $location.path so we can detect they have been called spyOn(common.logger, 'getLogFn').and.returnValue( - jasmine.createSpy('log') + jasmine.createSpy('log'), ); spyOn($location, 'path').and.returnValue(jasmine.createSpy('path')); @@ -281,10 +282,10 @@ describe('Proverb.Web -> app-> controllers ->', function () { // this.log("Activated Sage Details View"); // this.title = "Sage Details: " + this.sage.name; expect(sageDetailController.log).toHaveBeenCalledWith( - 'Activated Sage Details View' + 'Activated Sage Details View', ); expect(sageDetailController.title).toBe( - 'Sage Details: ' + sage_stub.name + 'Sage Details: ' + sage_stub.name, ); }); }); @@ -309,7 +310,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { // tests this code has executed: // this.$location.path("/sages/edit/" + this.sage.id); expect($location.path).toHaveBeenCalledWith( - '/sages/edit/' + sage_stub.id + '/sages/edit/' + sage_stub.id, ); }); }); diff --git a/blog-website/blog/2014-09-13-migrating-jasmine-tests-to-typescript/index.md b/blog-website/blog/2014-09-13-migrating-jasmine-tests-to-typescript/index.md index b7731347e89..9ae44d8d323 100644 --- a/blog-website/blog/2014-09-13-migrating-jasmine-tests-to-typescript/index.md +++ b/blog-website/blog/2014-09-13-migrating-jasmine-tests-to-typescript/index.md @@ -4,6 +4,7 @@ title: 'Journalling the Migration of Jasmine Tests to TypeScript' authors: johnnyreilly tags: [Jasmine, typescript, javascript] hide_table_of_contents: false +description: 'John describes issues migrating Jasmine tests from JS to TypeScript, including tooling, typings, and missing dependencies.' --- I previously attempted to migrate my Jasmine tests from JavaScript to TypeScript. The last time I tried it didn't go so well and I bailed. Thank the Lord for source control. But feeling I shouldn't be deterred I decided to have another crack at it. @@ -37,7 +38,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { _$q_, _$location_, _common_, - _datacontext_ + _datacontext_, ) { $rootScope = _$rootScope_; $q = _$q_; @@ -50,11 +51,11 @@ describe('Proverb.Web -> app-> controllers ->', function () { getById_deferred = $q.defer(); spyOn(datacontext.sage, 'getById').and.returnValue( - getById_deferred.promise + getById_deferred.promise, ); spyOn(common, 'activateController').and.callThrough(); spyOn(common.logger, 'getLogFn').and.returnValue( - jasmine.createSpy('log') + jasmine.createSpy('log'), ); spyOn($location, 'path').and.returnValue(jasmine.createSpy('path')); @@ -98,10 +99,10 @@ describe('Proverb.Web -> app-> controllers ->', function () { $rootScope.$digest(); // So Angular processes the resolved promise expect(sageDetailController.log).toHaveBeenCalledWith( - 'Activated Sage Details View' + 'Activated Sage Details View', ); expect(sageDetailController.title).toBe( - 'Sage Details: ' + sage_stub.name + 'Sage Details: ' + sage_stub.name, ); }); }); @@ -119,7 +120,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { sageDetailController.gotoEdit(); expect($location.path).toHaveBeenCalledWith( - '/sages/edit/' + sage_stub.id + '/sages/edit/' + sage_stub.id, ); }); }); @@ -223,7 +224,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { _$q_: ng.IQService, _$location_: ng.ILocationService, _common_: common, - _datacontext_: datacontext + _datacontext_: datacontext, ) { $rootScope = _$rootScope_; var $q = _$q_; @@ -236,11 +237,11 @@ describe('Proverb.Web -> app-> controllers ->', function () { getById_deferred = $q.defer(); spyOn(datacontext.sage, 'getById').and.returnValue( - getById_deferred.promise + getById_deferred.promise, ); spyOn(common, 'activateController').and.callThrough(); spyOn(common.logger, 'getLogFn').and.returnValue( - jasmine.createSpy('log') + jasmine.createSpy('log'), ); spyOn($location, 'path').and.returnValue(jasmine.createSpy('path')); @@ -290,10 +291,10 @@ describe('Proverb.Web -> app-> controllers ->', function () { $rootScope.$digest(); // So Angular processes the resolved promise expect(sageDetailController.log).toHaveBeenCalledWith( - 'Activated Sage Details View' + 'Activated Sage Details View', ); expect(sageDetailController.title).toBe( - 'Sage Details: ' + sage_stub.name + 'Sage Details: ' + sage_stub.name, ); }); }); @@ -317,7 +318,7 @@ describe('Proverb.Web -> app-> controllers ->', function () { sageDetailController.gotoEdit(); expect($location.path).toHaveBeenCalledWith( - '/sages/edit/' + sage_stub.id + '/sages/edit/' + sage_stub.id, ); }); }); diff --git a/blog-website/blog/2014-10-03-he-tasks-me-he-heaps-me-i-will-wreak/index.md b/blog-website/blog/2014-10-03-he-tasks-me-he-heaps-me-i-will-wreak/index.md index e2700e9d746..fdc31a6f0af 100644 --- a/blog-website/blog/2014-10-03-he-tasks-me-he-heaps-me-i-will-wreak/index.md +++ b/blog-website/blog/2014-10-03-he-tasks-me-he-heaps-me-i-will-wreak/index.md @@ -4,6 +4,7 @@ title: 'He tasks me; he heaps me.... I will wreak that MOQ upon him.' authors: johnnyreilly tags: [unit testing, MOQ] hide_table_of_contents: false +description: 'Use Moq to simplify async testing, with ReturnAsync method. For testing a class that consumes async API, mock it using Task.Delay with Moqs Returns.' --- Enough with the horrific misquotes - this is about Moq and async (that's my slight justification for robbing Herman Melville). diff --git a/blog-website/blog/2014-10-06-caching-and-cache-busting-in-angularjs-with-http-interceptors/index.md b/blog-website/blog/2014-10-06-caching-and-cache-busting-in-angularjs-with-http-interceptors/index.md index 91af5898342..cff954787ac 100644 --- a/blog-website/blog/2014-10-06-caching-and-cache-busting-in-angularjs-with-http-interceptors/index.md +++ b/blog-website/blog/2014-10-06-caching-and-cache-busting-in-angularjs-with-http-interceptors/index.md @@ -4,6 +4,7 @@ title: 'Caching and Cache-Busting in AngularJS with HTTP interceptors' authors: johnnyreilly tags: [typescript, AngularJS] hide_table_of_contents: false +description: 'Learn how to modify GET request URLs for static resources and AngularJS views with HTTP interceptors using version numbers and unique querystrings.' --- ## Loading On-Demand and Caching diff --git a/blog-website/blog/2014-11-04-using-gulp-in-visual-studio-instead-of-web-optimization/index.md b/blog-website/blog/2014-11-04-using-gulp-in-visual-studio-instead-of-web-optimization/index.md index 843c00cc51d..a3410ca2211 100644 --- a/blog-website/blog/2014-11-04-using-gulp-in-visual-studio-instead-of-web-optimization/index.md +++ b/blog-website/blog/2014-11-04-using-gulp-in-visual-studio-instead-of-web-optimization/index.md @@ -4,6 +4,7 @@ title: 'Using Gulp in Visual Studio instead of Web Optimization' authors: johnnyreilly tags: [Task Runner Explorer, Visual Studio, typescript, javascript, gulpjs] hide_table_of_contents: false +description: 'The ASP.NET team may replace Web Optimization with Grunt or Gulp. John Reilly tried out Gulp, which concatenates, minimises & version-numbers files.' --- ### Updated 17/02/2015: I've taken the approach discussed in this post a little further - you can see [here](../2012-10-05-using-web-optimization-with-mvc-3/index.md) @@ -244,7 +245,7 @@ function getManifest( manifestName, bundleName, includeRelativePath, - pathPrepend + pathPrepend, ) { // Determine filename ("./build/manifest-debug.json" or "./build/manifest-release.json" var manifestFile = @@ -298,7 +299,7 @@ gulp.task( //.pipe(ignore.exclude("**/*.{ts,js.map}")) // Exclude ts and js.map files from the manifest (as they won't become script tags) .pipe(getManifest(filesAndFolders.debug, bundleNames.styles, true)) ); - } + }, ); // Concatenate & Minify JS for release into a single file @@ -335,7 +336,7 @@ gulp.task('styles-release', ['clean'], function () { .pipe(minifyCss()) // Make the file titchy tiny small .pipe(rev()) // Suffix a version number to it .pipe( - gulp.dest(filesAndFolders.releaseFolder + '/' + filesAndFolders.css) + gulp.dest(filesAndFolders.releaseFolder + '/' + filesAndFolders.css), ) ); // Write single versioned file to build/release folder }); @@ -352,10 +353,10 @@ gulp.task( filesAndFolders.release, bundleNames.styles, false, - filesAndFolders.css + '/' - ) + filesAndFolders.css + '/', + ), ); - } + }, ); // Copy across all fonts in filesAndFolders.fonts to both release and debug locations @@ -482,7 +483,7 @@ That would be pretty simple - and for what it's worth \*\*simple is good Before I make all the changes let's review where we were. I had a single MVC view which, in terms of bundles, CSS and JavaScript pretty much looked like this: ```html - + @@ -494,23 +495,23 @@ Before I make all the changes let's review where we were. I had a single MVC vie @Scripts.Render("~/angularApp") @@ -522,7 +523,7 @@ This is already more a complicated example than most peoples use cases. Essentia After reading [an article about script loading by the magnificently funny Jake Archibald](http://www.html5rocks.com/en/tutorials/speed/script-loading/) I felt ready. I cast my MVC view to the four winds and created myself a straight HTML file: ```html - + diff --git a/blog-website/blog/2014-11-26-Coded-UI-IE-11-and-the-runas-problem/index.md b/blog-website/blog/2014-11-26-Coded-UI-IE-11-and-the-runas-problem/index.md index 55786979906..73aeaa252d2 100644 --- a/blog-website/blog/2014-11-26-Coded-UI-IE-11-and-the-runas-problem/index.md +++ b/blog-website/blog/2014-11-26-Coded-UI-IE-11-and-the-runas-problem/index.md @@ -4,6 +4,7 @@ title: "Pretending to be someone you're not and the dark pit of despair" authors: johnnyreilly tags: [Coded UI, internet explorer] hide_table_of_contents: false +description: 'Workaround for issues with Coded UI impersonation feature. Tests can be unreliable, but the fix works well.' --- ## Coded UI, IE 11 and the "runas" problem diff --git a/blog-website/blog/2014-12-05-whats-in-a-name/index.md b/blog-website/blog/2014-12-05-whats-in-a-name/index.md index c74f4e46aea..418ba3a2b54 100644 --- a/blog-website/blog/2014-12-05-whats-in-a-name/index.md +++ b/blog-website/blog/2014-12-05-whats-in-a-name/index.md @@ -3,6 +3,7 @@ slug: whats-in-a-name title: "What's in a (Domain) Name?" authors: johnnyreilly hide_table_of_contents: false +description: '"icanmakethiswork" blog has a new domain due to Johns concern about potential changes in Google hosting, now "blog.icanmakethiswork.io".' --- The observant amongst you may have noticed that this blog has a brand new and shiny domain name! That's right, after happily trading under "icanmakethiswork.blogspot.com" for the longest time it's now "blog.icanmakethiswork.io". Trumpets and fanfare! diff --git a/blog-website/blog/2014-12-12-gulp-npm-long-paths-and-visual-studio-fight/index.md b/blog-website/blog/2014-12-12-gulp-npm-long-paths-and-visual-studio-fight/index.md index bc056b00248..879f5944887 100644 --- a/blog-website/blog/2014-12-12-gulp-npm-long-paths-and-visual-studio-fight/index.md +++ b/blog-website/blog/2014-12-12-gulp-npm-long-paths-and-visual-studio-fight/index.md @@ -4,16 +4,17 @@ title: 'Gulp, npm, long paths and Visual Studio.... Fight!' authors: johnnyreilly tags: [npm, Visual Studio] hide_table_of_contents: false +description: 'Installing gulp-angular-templatecache plugin caused issues with Visual Studio. A temporary solution is to install lodash.bind at root level.' --- -## How I managed to gulp-angular-templatecache working inside Visual Studio - - +## How I managed to gulp-angular-templatecache working inside Visual Studio Every now and then something bites you unexpectedly. After a certain amount of pain, the answer comes to you and you know you want to save others from falling into the same deathtrap. There I was minding my own business and having a play with a Gulp plugin called [gulp-angular-templatecache](https://www.npmjs.com/package/gulp-angular-templatecache). If you're not aware of it, it "Concatenates and registers AngularJS templates in the $templateCache". I was planning to use it so that all the views in an [Angular app of mine](https://github.com/johnnyreilly/proverb-offline) were loaded up-front rather than on demand. (It's a first step in making an "offline-first" version of that particular app.) + + I digress already. No sooner had I tapped in: ```ps diff --git a/blog-website/blog/2014-12-29-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-1/index.md b/blog-website/blog/2014-12-29-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-1/index.md index 5d69c7a3d5b..8583da5dab7 100644 --- a/blog-website/blog/2014-12-29-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-1/index.md +++ b/blog-website/blog/2014-12-29-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-1/index.md @@ -4,6 +4,7 @@ title: 'Deploying from ASP.Net MVC to GitHub Pages using AppVeyor part 1' authors: johnnyreilly tags: [powershell, github pages, AppVeyor] hide_table_of_contents: false +description: 'John (creator of jQuery Validation Unobtrusive Native) found a way to use GitHub Pages and automate deployment by creating a static version of the app.' --- There's a small open source project I'm responsible for called [jQuery Validation Unobtrusive Native](https://github.com/johnnyreilly/jQuery.Validation.Unobtrusive.Native). (A catchy name is a must for any good open source project. Alas I'm not quite meeting my own exacting standards on this particular point... I should have gone with my gut and called it "Livingstone" instead. Too late now...) diff --git a/blog-website/blog/2015-01-07-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-2/index.md b/blog-website/blog/2015-01-07-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-2/index.md index 5b7ade54319..03ee7244e23 100644 --- a/blog-website/blog/2015-01-07-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-2/index.md +++ b/blog-website/blog/2015-01-07-deploying-aspnet-mvc-to-github-pages-with-appveyor-part-2/index.md @@ -11,6 +11,7 @@ tags: AppVeyor, ] hide_table_of_contents: false +description: 'To save time, automating open source projects is key. Using AppVeyor and creating static sites with tools like Wget can help update documentation.' --- "Automation, automation, automation." Those were and are Tony Blair's priorities for keeping open source projects well maintained. diff --git a/blog-website/blog/2015-01-20-typescript-using-functions-with-union-types/index.md b/blog-website/blog/2015-01-20-typescript-using-functions-with-union-types/index.md index 4518f536c0e..b0802858ce3 100644 --- a/blog-website/blog/2015-01-20-typescript-using-functions-with-union-types/index.md +++ b/blog-website/blog/2015-01-20-typescript-using-functions-with-union-types/index.md @@ -4,6 +4,7 @@ title: 'TypeScript: In Praise of Union Types' authors: johnnyreilly tags: [typescript, Union Types] hide_table_of_contents: false +description: 'TypeScript 1.4s Union Types offer a way to specify a value that is of one of many different types and results in a much terser definition file.' --- ## (& How to Express Functions in UTs) diff --git a/blog-website/blog/2015-02-11-the-convent-with-continuous-delivery/index.md b/blog-website/blog/2015-02-11-the-convent-with-continuous-delivery/index.md index ceb6737cc83..6258e93dc0a 100644 --- a/blog-website/blog/2015-02-11-the-convent-with-continuous-delivery/index.md +++ b/blog-website/blog/2015-02-11-the-convent-with-continuous-delivery/index.md @@ -4,6 +4,7 @@ title: 'The Convent with Continuous Delivery' authors: johnnyreilly tags: [Continuous Delivery, AppVeyor] hide_table_of_contents: false +description: 'Programmer has open-sourced the Poor Clares Arundel website, making tweaks and site updating easier, with continuous delivery and collaboration.' --- I've done it. I've open sourced the [website that I maintain for my aunt what is a nun](http://www.poorclaresarundel.org/). Because I think we can all agree that nuns need open source and continuous integration about as much as anyone else. diff --git a/blog-website/blog/2015-02-17-using-gulp-in-asp-net-instead-of-web-optimization/index.md b/blog-website/blog/2015-02-17-using-gulp-in-asp-net-instead-of-web-optimization/index.md index 068532b345f..6a8a311e052 100644 --- a/blog-website/blog/2015-02-17-using-gulp-in-asp-net-instead-of-web-optimization/index.md +++ b/blog-website/blog/2015-02-17-using-gulp-in-asp-net-instead-of-web-optimization/index.md @@ -4,6 +4,7 @@ title: 'Using Gulp to inject scripts and styles tags directly into your HTML' authors: johnnyreilly tags: [asp.net, Web Optimization, gulpjs] hide_table_of_contents: false +description: 'Learn how to use Gulp to directly inject scripts and styles into your HTML, which speeds up app times and makes the setup simpler.' --- This is very probably the dullest title for a blog post I've ever come up with. Read on though folks - it's definitely going to pick up... @@ -33,7 +34,7 @@ gulp-inject (as the name suggests) is used to inject `script` and `link` tags in So, let's get the launch page (`index.html`) ready for gulp-inject: ```html - + @@ -213,11 +214,11 @@ function getScriptsOrStyles(jsOrCss) { var bowerScriptsRelative = bowerScriptsAbsolute.map( function makePathRelativeToCwd(file) { return path.relative('', file); - } + }, ); var appScripts = bowerScriptsRelative.concat( - jsOrCss === 'js' ? config.scripts : config.styles + jsOrCss === 'js' ? config.scripts : config.styles, ); return appScripts; @@ -290,10 +291,10 @@ gulp.task('inject-debug', ['styles-debug', 'scripts-debug'], function () { config.debugFolder + '**/*.{js,css}', '!build\\debug\\bower_components\\spin.js', // Exclude weird spin js path ], - { read: false } + { read: false }, ) - .pipe(order(scriptsAndStyles)) - ) + .pipe(order(scriptsAndStyles)), + ), ) .pipe(gulp.dest(config.buildDir)); }); @@ -304,7 +305,7 @@ gulp.task('inject-release', ['styles-release', 'scripts-release'], function () { return gulp .src(config.bootFile) .pipe( - inject(gulp.src(config.releaseFolder + '**/*.{js,css}', { read: false })) + inject(gulp.src(config.releaseFolder + '**/*.{js,css}', { read: false })), ) .pipe(gulp.dest(config.buildDir)); }); diff --git a/blog-website/blog/2015-02-27-hey-tsconfigjson-where-have-you-been/index.md b/blog-website/blog/2015-02-27-hey-tsconfigjson-where-have-you-been/index.md index 70516eedcb9..ddcc274c06d 100644 --- a/blog-website/blog/2015-02-27-hey-tsconfigjson-where-have-you-been/index.md +++ b/blog-website/blog/2015-02-27-hey-tsconfigjson-where-have-you-been/index.md @@ -4,6 +4,7 @@ title: 'Hey tsconfig.json, where have you been all my life?' authors: johnnyreilly tags: [tsconfig.json, typescript] hide_table_of_contents: false +description: 'The creation of a "tsconfig.json" file will eliminate the need for "reference" comments when using TypeScript, reducing barriers between IDEs.' --- Sometimes, you just miss things. Something seismic happens and you had no idea. So it was with `tsconfig.json`. diff --git a/blog-website/blog/2015-03-20-partialview-tostring/index.md b/blog-website/blog/2015-03-20-partialview-tostring/index.md index 46ff967f9f6..0f9dd864626 100644 --- a/blog-website/blog/2015-03-20-partialview-tostring/index.md +++ b/blog-website/blog/2015-03-20-partialview-tostring/index.md @@ -4,6 +4,7 @@ title: 'PartialView.ToString()' authors: johnnyreilly tags: [asp.net mvc] hide_table_of_contents: false +description: 'Learn three ways to turn a `PartialViewResult` into a `string` to reuse the result returned by a controller in a JSON payload.' --- In the name of [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) I found myself puzzling how one could take a `PartialViewResult` and render it as a `string`. Simple, right? diff --git a/blog-website/blog/2015-04-17-how-to-activate-your-emoji-keyboard-on-android/index.md b/blog-website/blog/2015-04-17-how-to-activate-your-emoji-keyboard-on-android/index.md index e77e2c758d2..8350f3bc9e5 100644 --- a/blog-website/blog/2015-04-17-how-to-activate-your-emoji-keyboard-on-android/index.md +++ b/blog-website/blog/2015-04-17-how-to-activate-your-emoji-keyboard-on-android/index.md @@ -4,6 +4,7 @@ title: 'How to activate your emoji keyboard on Android 5.0 (Lollipop)' authors: johnnyreilly tags: [android] hide_table_of_contents: false +description: 'Learn how to get emoji on your Android phone by activating the "iWnn IME Japanese" keyboard and selecting the "Emoji" option.' --- A departure from from my normal content - I need to tell you about [emoji](http://en.wikipedia.org/wiki/Emoji)! You'll probably already know about them - just imagine a emoticon but about 300,000 times better. They really add spice to to textual content. Oh and they're Japanese - which is also way cool. diff --git a/blog-website/blog/2015-04-24-tonight-ill-start-open-source-project/index.md b/blog-website/blog/2015-04-24-tonight-ill-start-open-source-project/index.md index 09812306c3d..db928460c6b 100644 --- a/blog-website/blog/2015-04-24-tonight-ill-start-open-source-project/index.md +++ b/blog-website/blog/2015-04-24-tonight-ill-start-open-source-project/index.md @@ -4,6 +4,7 @@ title: "Tonight I'll Start an Open Source Project..." authors: johnnyreilly tags: [asp.net mvc, validation, AngularJS] hide_table_of_contents: false +description: 'A new AngularJS validation mechanism aims to propagate data annotations on ASP.NET MVC server models into ng-* directive attributes in HTML.' --- ### Further posts on this topic @@ -125,8 +126,14 @@ I could tweak it to push in the validation directive attributes like this:
diff --git a/blog-website/blog/2015-05-05-a-tale-of-angular-html5mode-aspnet-mvc/index.md b/blog-website/blog/2015-05-05-a-tale-of-angular-html5mode-aspnet-mvc/index.md index e2b848bacc4..15d0cc23f88 100644 --- a/blog-website/blog/2015-05-05-a-tale-of-angular-html5mode-aspnet-mvc/index.md +++ b/blog-website/blog/2015-05-05-a-tale-of-angular-html5mode-aspnet-mvc/index.md @@ -4,6 +4,7 @@ title: 'A tale of Angular, html5mode, ASP.Net MVC and ASP.Net Web API' authors: johnnyreilly tags: [asp.net, AngularJS] hide_table_of_contents: false +description: 'This article offers tips on how to preserve specific routes while redirecting non-specified URLs to the root angular app page for ASP.Net MVC and Web API.' --- So. You want to kick hash based routing to the kerb. You want _real_ URLs. You've read the HTML5 mode section of the [Angular $location docs](https://docs.angularjs.org/guide/$location) and you're good to go. It's just a matter of dropping `$locationProvider.html5Mode(true)` into your app initialisation right? diff --git a/blog-website/blog/2015-05-11-ngvalidationfor-baby-steps/index.md b/blog-website/blog/2015-05-11-ngvalidationfor-baby-steps/index.md index d19fa2ee088..9eb164166b4 100644 --- a/blog-website/blog/2015-05-11-ngvalidationfor-baby-steps/index.md +++ b/blog-website/blog/2015-05-11-ngvalidationfor-baby-steps/index.md @@ -4,6 +4,7 @@ title: 'NgValidationFor Baby Steps' authors: johnnyreilly tags: [asp.net mvc, AngularJS] hide_table_of_contents: false +description: 'The NgValidationFor project translates data annotations to Angular validation directive attributes while minimising dependencies.' --- I thought as I start the [NgValidationFor project](../2015-04-24-tonight-ill-start-open-source-project/index.md) I'd journal my progress. I'm writing this with someone particular in mind: me. Specifically, me in 2 years who will no doubt wonder why I made some of the choices I did. Everyone else, move along now - nothing to see. Unless the inner workings of someone else's mind are interesting to you... In which case: welcome! @@ -48,8 +49,14 @@ When used in an MVC View for which `RequiredDemoModel` is the Model, NgValiditio ```html @using NgValidationFor.Core @using NgValidationFor.Documentation.Models @model -RequiredDemoModel Model.RequiredField)) > +RequiredDemoModel + +Model.RequiredField)) > ``` Which results in this HTML: diff --git a/blog-website/blog/2015-05-23-angular-ui-bootstrap-datepicker-weirdness/index.md b/blog-website/blog/2015-05-23-angular-ui-bootstrap-datepicker-weirdness/index.md index d65b0928eb9..0a4de36ebd6 100644 --- a/blog-website/blog/2015-05-23-angular-ui-bootstrap-datepicker-weirdness/index.md +++ b/blog-website/blog/2015-05-23-angular-ui-bootstrap-datepicker-weirdness/index.md @@ -4,6 +4,7 @@ title: 'Angular UI Bootstrap Datepicker Weirdness' authors: johnnyreilly tags: [Bootstrap, AngularJS] hide_table_of_contents: false +description: 'Add a calendar glyph to your Angular UI Bootstrap Datepicker popup by passing along $event and calling stopPropagation() to avoid an issue.' --- The [Angular UI Bootstrap Datepicker](https://angular-ui.github.io/bootstrap/#/datepicker) is fan-dabby-dozy. But it has a ... pecularity. You can use the picker like this: diff --git a/blog-website/blog/2015-06-19-Back-to-the-Future-with-Code-First-Migrations/index.md b/blog-website/blog/2015-06-19-Back-to-the-Future-with-Code-First-Migrations/index.md index b01d380000e..6c0b2d29a3d 100644 --- a/blog-website/blog/2015-06-19-Back-to-the-Future-with-Code-First-Migrations/index.md +++ b/blog-website/blog/2015-06-19-Back-to-the-Future-with-Code-First-Migrations/index.md @@ -4,6 +4,7 @@ title: 'Back to the Future with Code First Migrations' authors: johnnyreilly tags: [Entity Framework] hide_table_of_contents: false +description: 'Code First Migrations order is determined by file name, not renaming, and requires changing the IMigrationMetadata.Id property to match.' --- Code First Migrations. They look a little like this in Visual Studio: diff --git a/blog-website/blog/2015-06-29-npm-please-stop-hurting-visual-studio/index.md b/blog-website/blog/2015-06-29-npm-please-stop-hurting-visual-studio/index.md index 1b2949ebaad..9c16f8a8987 100644 --- a/blog-website/blog/2015-06-29-npm-please-stop-hurting-visual-studio/index.md +++ b/blog-website/blog/2015-06-29-npm-please-stop-hurting-visual-studio/index.md @@ -4,6 +4,7 @@ title: 'npm please stop hurting Visual Studio' authors: johnnyreilly tags: [npm, Windows] hide_table_of_contents: false +description: 'Windows handling of long paths can be problematic when using Visual Studio with npm; using rimraf for deletions can help until npm 3.0 comes out.' --- I don't know about you but I personally feel that the following sentence may well be the saddest in the English language: diff --git a/blog-website/blog/2015-07-30-upgrading-to-globalize-1x-for-dummies/index.md b/blog-website/blog/2015-07-30-upgrading-to-globalize-1x-for-dummies/index.md index d7b2c1a2333..7abd94f366b 100644 --- a/blog-website/blog/2015-07-30-upgrading-to-globalize-1x-for-dummies/index.md +++ b/blog-website/blog/2015-07-30-upgrading-to-globalize-1x-for-dummies/index.md @@ -4,6 +4,7 @@ title: 'Upgrading to Globalize 1.x for Dummies' authors: johnnyreilly tags: [Globalize] hide_table_of_contents: false +description: 'Migrating to Globalize 1.0, which modularized the code, requires a significant amount of work, as shown by John Reilly’s examples.' --- Globalize has hit 1.0. Anyone who reads my blog will likely be aware that I'm a long time user of [Globalize 0.1.x](../2012-05-07-globalizejs-number-and-date/index.md). I've been a little daunted by the leap that the move from 0.1.x to 1.x represents. It appears to be the very definition of "breaking changes". :-) But hey, this is Semantic Versioning being used correctly so how could I complain? Either way, I've decided to write up the migration here as I'm not expecting this to be easy. @@ -47,11 +48,11 @@ To kick things off I've set up a very [simple repo](https://github.com/johnnyrei document.querySelector('#date').innerText = date; document.querySelector('#numberFormatted').innerText = Globalize.format( number, - 'n2' + 'n2', ); document.querySelector('#dateFormatted').innerText = Globalize.format( date, - 'd' + 'd', ); @@ -259,10 +260,10 @@ To do this I'm going to lean heavily upon [an example put together by Rafael](ht // Date fetch( - 'bower_components/cldr-data/main/' + locale + '/ca-gregorian.json' + 'bower_components/cldr-data/main/' + locale + '/ca-gregorian.json', ), fetch( - 'bower_components/cldr-data/main/' + locale + '/timeZoneNames.json' + 'bower_components/cldr-data/main/' + locale + '/timeZoneNames.json', ), fetch('bower_components/cldr-data/supplemental/timeData.json'), fetch('bower_components/cldr-data/supplemental/weekData.json'), @@ -275,7 +276,7 @@ To do this I'm going to lean heavily upon [an example put together by Rafael](ht return Promise.all( responses.map(function (response) { return response.json(); - }) + }), ); }) .then(Globalize.load) @@ -346,7 +347,7 @@ gulp.task('make-globalize-culture-de-js', function () { } else { console.log('The file was created!'); } - } + }, ); }); ``` diff --git a/blog-website/blog/2015-08-13-top-one-nice-one-get-sorted/index.md b/blog-website/blog/2015-08-13-top-one-nice-one-get-sorted/index.md index 504cc76ae38..e24ffb5055f 100644 --- a/blog-website/blog/2015-08-13-top-one-nice-one-get-sorted/index.md +++ b/blog-website/blog/2015-08-13-top-one-nice-one-get-sorted/index.md @@ -4,6 +4,7 @@ title: '(Top One, Nice One) Get Sorted' authors: johnnyreilly tags: [javascript, LINQ] hide_table_of_contents: false +description: 'John creates a way to use .NETs LINQ feature to sort JavaScript arrays. The tools allow sorting by one or more criteria.' --- I was recently reading [a post by Jaime González García](http://www.barbarianmeetscoding.com/blog/2015/07/09/mastering-the-arcane-art-of-javascript-mancy-for-c-sharp-developers-chapter-7-using-linq-in-javascript/) which featured the following mind-bending proposition: @@ -108,7 +109,7 @@ If we use the `numberComparer` on our original array it looks like this: ```js const foodInTheHouseSorted = foodInTheHouse.sort( - numberComparer((x) => x.daysSincePurchase) + numberComparer((x) => x.daysSincePurchase), ); // foodInTheHouseSorted: [ @@ -147,7 +148,7 @@ Which is more optimal and even simpler as it just swaps the values supplied to t ```js const foodInTheHouseSorted = foodInTheHouse.sort( - reverse(stringComparer((x) => x.what)) + reverse(stringComparer((x) => x.what)), ); // foodInTheHouseSorted: [ @@ -181,8 +182,8 @@ This fine function takes any number of comparers that have been supplied to it. const foodInTheHouseSorted = foodInTheHouse.sort( composeComparers( stringComparer((x) => x.what), - numberComparer((x) => x.daysSincePurchase) - ) + numberComparer((x) => x.daysSincePurchase), + ), ); // foodInTheHouseSorted: [ @@ -280,7 +281,7 @@ You want to do this with TypeScript? Use this: type Comparer = (obj1: TObject, obj2: TObject) => number; export function stringComparer( - propLambda: (obj: TObject) => string + propLambda: (obj: TObject) => string, ): Comparer { return (obj1: TObject, obj2: TObject) => { const obj1Val = propLambda(obj1) || ''; @@ -290,7 +291,7 @@ export function stringComparer( } export function numberComparer( - propLambda: (obj: TObject) => number + propLambda: (obj: TObject) => number, ): Comparer { return (obj1: TObject, obj2: TObject) => { const obj1Val = propLambda(obj1); diff --git a/blog-website/blog/2015-09-10-things-done-changed/index.md b/blog-website/blog/2015-09-10-things-done-changed/index.md index f8f7642d73b..5e54ee5173b 100644 --- a/blog-website/blog/2015-09-10-things-done-changed/index.md +++ b/blog-website/blog/2015-09-10-things-done-changed/index.md @@ -4,6 +4,7 @@ title: 'Things Done Changed' authors: johnnyreilly tags: [ES6, Atom, Babel, React, WebSockets] hide_table_of_contents: false +description: 'Embracing change is key to being a developer; John discusses some of the tools that have taken his fancy, including React and ES6.' --- Some people fear change. Most people actually. I'm not immune to that myself, but not in the key area of technology. Any developer that fears change when it comes to the tools and languages that he / she is using is in the _wrong_ business. Because what you're using to cut code today will not last. The language will evolve, the tools and frameworks that you love will die out and be replaced by new ones that are different and strange. In time, the language you feel you write as a native will fall out of favour, replaced by a new upstart. diff --git a/blog-website/blog/2015-09-23-authoring-npm-modules-with-typescript/index.md b/blog-website/blog/2015-09-23-authoring-npm-modules-with-typescript/index.md index d886fde42bd..20e0437214a 100644 --- a/blog-website/blog/2015-09-23-authoring-npm-modules-with-typescript/index.md +++ b/blog-website/blog/2015-09-23-authoring-npm-modules-with-typescript/index.md @@ -4,6 +4,7 @@ title: "Definitely Typed Shouldn't Exist" authors: johnnyreilly tags: [npm, DefinitelyTyped, typescript] hide_table_of_contents: false +description: 'Using TypeScript definition files with npm packages can produce accurate typing information. Making npm a first class citizen may replace Definitely Typed.' --- OK - the title's total clickbait but stay with me; there's a point here. @@ -166,7 +167,7 @@ function determineRequiredCldrData(globalizeOptions) { globalizeOptions, _populateDependencyCurrier('json', function (json) { return json.dependency; - }) + }), ); } @@ -177,8 +178,8 @@ function determineRequiredCldrGlobalizeFiles(globalizeOptions) { 'cldrGlobalizeFiles', function (cldrGlobalizeFile) { return cldrGlobalizeFile; - } - ) + }, + ), ); } @@ -401,7 +402,7 @@ function determineRequiredCldrData(globalizeOptions) { globalizeOptions, _populateDependencyCurrier('json', function (json) { return json.dependency; - }) + }), ); } exports.determineRequiredCldrData = determineRequiredCldrData; @@ -417,8 +418,8 @@ function determineRequiredCldrGlobalizeFiles(globalizeOptions) { 'cldrGlobalizeFiles', function (cldrGlobalizeFile) { return cldrGlobalizeFile; - } - ) + }, + ), ); } exports.determineRequiredCldrGlobalizeFiles = @@ -444,7 +445,7 @@ export interface Options { * @param options The globalize modules being used. */ export declare function determineRequiredCldrData( - globalizeOptions: Options + globalizeOptions: Options, ): string[]; /** * The string array returned will contain a list of the required cldr / globalize files you need, listed in the order they are required. @@ -452,7 +453,7 @@ export declare function determineRequiredCldrData( * @param options The globalize modules being used. */ export declare function determineRequiredCldrGlobalizeFiles( - globalizeOptions: Options + globalizeOptions: Options, ): string[]; ``` diff --git a/blog-website/blog/2015-10-05-jquery-validation-globalize-hits-10/index.md b/blog-website/blog/2015-10-05-jquery-validation-globalize-hits-10/index.md index f70a2e4f21d..306b951d840 100644 --- a/blog-website/blog/2015-10-05-jquery-validation-globalize-hits-10/index.md +++ b/blog-website/blog/2015-10-05-jquery-validation-globalize-hits-10/index.md @@ -4,6 +4,7 @@ title: 'jQuery Validation Globalize hits 1.0' authors: johnnyreilly tags: [Globalize, jQuery Validation] hide_table_of_contents: false +description: 'jQuery Validation Globalize plugin now supports Globalize 1.x, with minor code changes. Users can customize date parsing format.' --- This is just a quick post - the tl;dr is this: jQuery Validation Globalize has been ported to Globalize 1.x. Yay! In one of those twists of fate I'm not actually using this plugin in my day job anymore but I thought it might be useful to other people. So here you go. You can read more about this plugin in an [older post](../2012-09-06-globalize-and-jquery-validate/index.md) and you can see a demo of it in action [here](http://johnnyreilly.github.io/jQuery.Validation.Unobtrusive.Native/AdvancedDemo/Globalize.html). @@ -82,7 +83,7 @@ To this: $.validator.methods.date = function (value, element) { var val = Globalize.parseDate( value, - $.validator.methods.dateGlobalizeOptions.dateParseFormat + $.validator.methods.dateGlobalizeOptions.dateParseFormat, ); return this.optional(element) || val instanceof Date; }; diff --git a/blog-website/blog/2015-10-23-the-names-have-been-changed/index.md b/blog-website/blog/2015-10-23-the-names-have-been-changed/index.md index 7158ceb3973..348f1285a27 100644 --- a/blog-website/blog/2015-10-23-the-names-have-been-changed/index.md +++ b/blog-website/blog/2015-10-23-the-names-have-been-changed/index.md @@ -4,6 +4,7 @@ title: 'The Names Have Been Changed...' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'John changes the domain name of his blog from .io to .com to save money and has set up a redirect from old site to new one.' --- ...to protect my wallet. diff --git a/blog-website/blog/2015-11-30-iqueryable-ienumerable-hmmm/index.md b/blog-website/blog/2015-11-30-iqueryable-ienumerable-hmmm/index.md index a1648164d19..012907015b1 100644 --- a/blog-website/blog/2015-11-30-iqueryable-ienumerable-hmmm/index.md +++ b/blog-website/blog/2015-11-30-iqueryable-ienumerable-hmmm/index.md @@ -4,6 +4,7 @@ title: 'IQueryable... IEnumerable... Hmmm...' authors: johnnyreilly tags: [LINQ] hide_table_of_contents: false +description: 'The debate surrounding passing IQueryable as IEnumerable is discussed. Changing the method signature is proposed as a solution.' --- So there I was, tip-tapping away at my keyboard when I became aware of the slowly loudening noise of a debate. It wasn't about poverty, war, civil rights or anything like that. No; this was far more contentious. It was about the behaviour of `IQueryable<T>` when mixed with `IEnumerable<T>`. I know, right, how could I not get involved? diff --git a/blog-website/blog/2015-12-16-es6-typescript-babel-react-flux-karma/index.md b/blog-website/blog/2015-12-16-es6-typescript-babel-react-flux-karma/index.md index f32892dd936..c407f6d8b64 100644 --- a/blog-website/blog/2015-12-16-es6-typescript-babel-react-flux-karma/index.md +++ b/blog-website/blog/2015-12-16-es6-typescript-babel-react-flux-karma/index.md @@ -4,6 +4,7 @@ title: 'ES6 + TypeScript + Babel + React + Flux + Karma: The Secret Recipe' authors: johnnyreilly tags: [ES6, Karma, React, ts-loader, webpack] hide_table_of_contents: false +description: 'Learn how to set up a powerful TypeScript-React workflow with webpack, gulp, Karma, and inject in this comprehensive article.' --- I wrote [a while ago](../2015-09-10-things-done-changed/index.md) about how I was using some different tools in a current project: @@ -26,7 +27,7 @@ But the pain is over. The dark days are gone. It's possible to have strong typin I decided a couple of months ago what I wanted to have in my setup: 1. I want to be able to write React / JSX in TypeScript. Naturally I couldn't achieve that by myself but handily the TypeScript team decided to add support for JSX with [TypeScript 1.6](https://blogs.msdn.com/b/typescript/archive/2015/09/16/announcing-typescript-1-6.aspx). Ooh yeah. -2. I wanted to be able to write ES6. When I realised [the approach for writing ES6 and having the transpilation handled by TypeScript wasn't clear](https://github.com/Microsoft/TypeScript/issues/3956) I had another idea. I thought ["what if I write ES6 and hand off the transpilation to Babel?"](https://github.com/Microsoft/TypeScript/issues/4765) i.e. Use TypeScript for type checking, not for transpilation. I realised that [James Brantly had my back](http://www.jbrantly.com/es6-modules-with-typescript-and-webpack/#configuringwebpack) here already. Enter [Webpack](https://webpack.github.io/) and [ts-loader](https://github.com/TypeStrong/ts-loader). +2. I wanted to be able to write ES6. When I realised [the approach for writing ES6 and having the transpilation handled by TypeScript wasn't clear](https://github.com/Microsoft/TypeScript/issues/3956) I had another idea. I thought ["what if I write ES6 and hand off the transpilation to Babel?"](https://github.com/Microsoft/TypeScript/issues/4765) i.e. Use TypeScript for type checking, not for transpilation. I realised that [James Brantly had my back](http://www.jbrantly.com/es6-modules-with-typescript-and-webpack/#configuringwebpack) here already. Enter [webpack](https://webpack.github.io/) and [ts-loader](https://github.com/TypeStrong/ts-loader). 3. Debugging. Being able to debug my code is non-negotiable for me. If I can't debug it I'm less productive. (I'm also bitter and twisted inside.) I should say that I wanted to be able to debug my _original_ source code. Thanks to the magic of [sourcemaps](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?usp=sharing), that mad thing is possible. 4. Karma for unit testing. I've become accustomed to writing my tests in ES6 and running them on a continual basis with [Karma](https://karma-runner.github.io/0.13/index.html). This allows for a rather good debugging story as well. I didn't want to lose this when I moved to TypeScript. I didn't. @@ -65,7 +66,7 @@ gulp.task( webpack.build().then(function () { done(); }); - } + }, ); gulp.task( @@ -73,7 +74,7 @@ gulp.task( ['delete-dist', 'build-process.env.NODE_ENV'], function () { staticFiles.build(); - } + }, ); gulp.task('build', ['build-js', 'build-other', 'lint'], function () { @@ -92,7 +93,7 @@ gulp.task('watch', ['delete-dist'], function () { ]) .then(function () { gutil.log( - 'Now that initial assets (js and css) are generated inject will start...' + 'Now that initial assets (js and css) are generated inject will start...', ); inject.watch(postInjectCb); }) @@ -165,7 +166,7 @@ function buildProduction(done) { filename: 'vendor.[hash].js', }), new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin() + new webpack.optimize.UglifyJsPlugin(), ); // run webpack @@ -177,7 +178,7 @@ function buildProduction(done) { '[webpack:build]', stats.toString({ colors: true, - }) + }), ); if (done) { @@ -198,7 +199,10 @@ function createDevCompiler() { name: 'vendor', filename: 'vendor.js', }), - new WebpackNotifierPlugin({ title: 'Webpack build', excludeWarnings: true }) + new WebpackNotifierPlugin({ + title: 'webpack build', + excludeWarnings: true, + }), ); // create a single instance of the compiler to allow caching @@ -216,7 +220,7 @@ function buildDevelopment(done, devCompiler) { stats.toString({ chunks: false, // dial down the output from webpack (it can be noisy) colors: true, - }) + }), ); if (done) { @@ -327,7 +331,7 @@ module.exports = { Your compiled output needs to be referenced from some kind of HTML page. So we've got this: ```html - + @@ -377,7 +381,7 @@ function injectIndex(options) { './dist/scripts/vendor*.js', './dist/scripts/main*.js', ], - { read: false } + { read: false }, ); return target @@ -397,7 +401,7 @@ function injectIndex(options) { ignorePath: '/dist/', addRootSlash: false, removeTags: true, - }) + }), ) .pipe(gulp.dest('./dist')); } diff --git a/blog-website/blog/2015-12-20-live-reload-considered-harmful/index.md b/blog-website/blog/2015-12-20-live-reload-considered-harmful/index.md index 5332b077d22..855d46f85c2 100644 --- a/blog-website/blog/2015-12-20-live-reload-considered-harmful/index.md +++ b/blog-website/blog/2015-12-20-live-reload-considered-harmful/index.md @@ -4,6 +4,7 @@ title: 'Live Reload Considered Harmful' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'Live Reload is a popular development tool that refreshes web pages automatically, however, its usefulness is questionable. It can disrupt app design.' --- I've seen it go by many names; [live reload](http://livereload.com/), hot reload, [browser sync](https://browsersync.io/)... the list goes on. It's been the subject of a million demos. It's the focus of a thousand npm packages. Someone tweaks a file and... wait for it... _doesn't have to refresh their browser to see the changes_... The future is now! diff --git a/blog-website/blog/2016-01-01-usestaticfiles-for-aspnet-vold/index.md b/blog-website/blog/2016-01-01-usestaticfiles-for-aspnet-vold/index.md index df3d33a77cd..d0134b64c47 100644 --- a/blog-website/blog/2016-01-01-usestaticfiles-for-aspnet-vold/index.md +++ b/blog-website/blog/2016-01-01-usestaticfiles-for-aspnet-vold/index.md @@ -4,6 +4,7 @@ title: 'UseStaticFiles for ASP.Net Framework' authors: johnnyreilly tags: [ASP.NET] hide_table_of_contents: false +description: 'Learn how to prevent exposing static files to the public when working with ASP.Net Framework. Discover how to implement an allowlist approach.' --- This is a guide on how _not_ to expose all your static files to the world at large when working with the ASP.Net Framework. How to move from a blocklisting approach to a allowlisting approach. diff --git a/blog-website/blog/2016-01-14-coded-ui-and-curse-of-docking-station/index.md b/blog-website/blog/2016-01-14-coded-ui-and-curse-of-docking-station/index.md index 855538241d0..7b9804324c7 100644 --- a/blog-website/blog/2016-01-14-coded-ui-and-curse-of-docking-station/index.md +++ b/blog-website/blog/2016-01-14-coded-ui-and-curse-of-docking-station/index.md @@ -4,6 +4,7 @@ title: 'Coded UI and the Curse of the Docking Station' authors: johnnyreilly tags: [Surface Pro 3, Coded UI] hide_table_of_contents: false +description: 'Coded UI tests struggle with docking stations due to resolution changes, causing the mouse to miss the element its aiming for.' --- I’ve a love / hate relationship with Coded UI. Well hate / hate might be more accurate. Hate perhaps married with a very grudging respect still underpinned by a wary bitterness. Yes, that’s about the size of it. Why? Well, when Coded UI works, it’s fab. But it’s flaky as anything. Anybody who’s used the technology is presently nodding sagely and holding back the tears. It’s all a bit... tough. diff --git a/blog-website/blog/2016-02-01-tfs-2012-net-45-and-c-6/index.md b/blog-website/blog/2016-02-01-tfs-2012-net-45-and-c-6/index.md index c89b2b9e391..9f3e5ff6514 100644 --- a/blog-website/blog/2016-02-01-tfs-2012-net-45-and-c-6/index.md +++ b/blog-website/blog/2016-02-01-tfs-2012-net-45-and-c-6/index.md @@ -4,6 +4,7 @@ title: 'TFS 2012, .NET 4.5 and C# 6' authors: johnnyreilly tags: [C#, .NET Framework, TFS] hide_table_of_contents: false +description: 'Use C# 6 features on .NET 4.5 with Visual Studio 2015, set MSBuild Arguments and install Microsoft.Net.Compilers on the old build server.' --- So, you want to use C# 6 language features and you’re working on an older project that’s still rocking .NET 4.5. Well, with [some caveats](http://stackoverflow.com/a/28921749/761388), you can. diff --git a/blog-website/blog/2016-02-19-visual-studio-tsconfigjson-and-external/index.md b/blog-website/blog/2016-02-19-visual-studio-tsconfigjson-and-external/index.md index 7eef7b60f51..2abc937d581 100644 --- a/blog-website/blog/2016-02-19-visual-studio-tsconfigjson-and-external/index.md +++ b/blog-website/blog/2016-02-19-visual-studio-tsconfigjson-and-external/index.md @@ -2,8 +2,9 @@ slug: visual-studio-tsconfigjson-and-external title: 'Visual Studio, tsconfig.json and external TypeScript compilation' authors: johnnyreilly -tags: [TFS, Visual Studio, tsconfig.json, typescript, Webpack] +tags: [TFS, Visual Studio, tsconfig.json, typescript, webpack] hide_table_of_contents: false +description: 'Visual Studio will not gain support for tsconfig.json until TypeScript 1.8, so using external compilation may be preferable.' --- TypeScript first gained support for [`tsconfig.json`](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json) back with the [1\.5 release](https://blogs.msdn.microsoft.com/typescript/2015/07/20/announcing-typescript-1-5/). However, to my lasting regret and surprise Visual Studio will not be gaining meaningful support for it until [TypeScript 1.8](https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#improved-support-for-tsconfigjson-in-visual-studio-2015) ships. However, if you want it now, it's already available to use in [beta](https://blogs.msdn.microsoft.com/typescript/2016/01/28/announcing-typescript-1-8-beta/). diff --git a/blog-website/blog/2016-02-29-creating-angular-ui-routes-in-controller/index.md b/blog-website/blog/2016-02-29-creating-angular-ui-routes-in-controller/index.md index 0e1d2dfea25..6a5e51a57e9 100644 --- a/blog-website/blog/2016-02-29-creating-angular-ui-routes-in-controller/index.md +++ b/blog-website/blog/2016-02-29-creating-angular-ui-routes-in-controller/index.md @@ -4,6 +4,7 @@ title: 'Creating Angular UI Routes in the Controller' authors: johnnyreilly tags: [AngularJS] hide_table_of_contents: false +description: 'Dont let your Angular UI Router link get too big - move the URL generation to the controller! Use the $state.href() method instead of ui-sref.' --- So you're creating a link with the Angular UI Router. You're passing more than a few parameters and it's getting kinda big. Something like this: diff --git a/blog-website/blog/2016-03-04-tfs-2012-meet-powershell-karma-and-buildnumber/index.md b/blog-website/blog/2016-03-04-tfs-2012-meet-powershell-karma-and-buildnumber/index.md index fa7fe081461..a038e6fb7c3 100644 --- a/blog-website/blog/2016-03-04-tfs-2012-meet-powershell-karma-and-buildnumber/index.md +++ b/blog-website/blog/2016-03-04-tfs-2012-meet-powershell-karma-and-buildnumber/index.md @@ -4,6 +4,7 @@ title: 'TFS 2012 meet PowerShell, Karma and BuildNumber' authors: johnnyreilly tags: [TFS] hide_table_of_contents: false +description: 'This guide explains how to run PowerShell scripts for TFS 2012 build processes and how to publish Karma test results in the platform.' --- To my lasting regret, TFS 2012 has no direct support for PowerShell. Such a shame as PowerShell scripts can do a lot of heavy lifting in a build process. Well, here we're going to brute force TFS 2012 into running PowerShell scripts. And along the way we'll also get Karma test results publishing into TFS 2012 as an example usage. Nice huh? Let's go! @@ -44,7 +45,7 @@ And _replace_ it with this: '/p:SkipInvalidConfigurations=true /p:BuildNumber={1} /p:BuildDefinitionName={2} {0}', MSBuildArguments, BuildDetail.BuildNumber, - BuildDetail.BuildDefinition.Name + BuildDetail.BuildDefinition.Name, ), ]; ``` diff --git a/blog-website/blog/2016-03-17-atom-recovering-from-corrupted-packages/index.md b/blog-website/blog/2016-03-17-atom-recovering-from-corrupted-packages/index.md index 45b787cd5ef..22885ba02c6 100644 --- a/blog-website/blog/2016-03-17-atom-recovering-from-corrupted-packages/index.md +++ b/blog-website/blog/2016-03-17-atom-recovering-from-corrupted-packages/index.md @@ -4,6 +4,7 @@ title: 'Atom - Recovering from Corrupted Packages' authors: johnnyreilly tags: [Atom] hide_table_of_contents: false +description: 'Atom packages corrupt? Locate `.apm` folder at `[Your name]/.atom`, then delete. On reopening Atom, packages will be restored.' --- Every now and then when I try and update my packages in [Atom](https://atom.io/) I find this glaring back at me: diff --git a/blog-website/blog/2016-03-22-concatting-ienumerables-in-csharp/index.md b/blog-website/blog/2016-03-22-concatting-ienumerables-in-csharp/index.md index e73d6437418..54cf8488a4b 100644 --- a/blog-website/blog/2016-03-22-concatting-ienumerables-in-csharp/index.md +++ b/blog-website/blog/2016-03-22-concatting-ienumerables-in-csharp/index.md @@ -4,6 +4,7 @@ title: 'Concatting IEnumerables in C#' authors: johnnyreilly tags: [C#] hide_table_of_contents: false +description: 'Author proposes clean alternatives to `IEnumerable`s concatenation which entail creating custom extensions & using nulls for null-conditional operator.' --- I hate LINQ's [`Enumerable.Concat`](https://msdn.microsoft.com/en-us/library/bb302894%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) when bringing together `IEnumerable`s. Not the behaviour (I love that!) but rather how code ends up looking when you use it. Consider this: diff --git a/blog-website/blog/2016-04-25-instant-stubs-with-jsonnet/index.md b/blog-website/blog/2016-04-25-instant-stubs-with-jsonnet/index.md index e8d2b8d3604..9336f33ba0b 100644 --- a/blog-website/blog/2016-04-25-instant-stubs-with-jsonnet/index.md +++ b/blog-website/blog/2016-04-25-instant-stubs-with-jsonnet/index.md @@ -4,6 +4,7 @@ title: 'Instant Stubs with JSON.Net (just add hot water)' authors: johnnyreilly tags: [unit testing, json.net] hide_table_of_contents: false +description: 'A utility class can create stubs to test an untested system with complex I/O. Serializing complex data to JSON files eases the process.' --- I'd like you to close your eyes and imagine a scenario. You're handed a prototype system. You're told it works. It has no documentation. It has 0 unit tests. The hope is that you can take it on, refactor it, make it better and (crucially) not break it. Oh, and you don't really understand what the code does or why it does it either; information on that front is, alas, sorely lacking. diff --git a/blog-website/blog/2016-05-13-inlining-angular-templates-with-webpack/index.md b/blog-website/blog/2016-05-13-inlining-angular-templates-with-webpack/index.md index 796a6dfb649..a7c30fcc6a0 100644 --- a/blog-website/blog/2016-05-13-inlining-angular-templates-with-webpack/index.md +++ b/blog-website/blog/2016-05-13-inlining-angular-templates-with-webpack/index.md @@ -4,6 +4,7 @@ title: 'Inlining Angular Templates with WebPack and TypeScript' authors: johnnyreilly tags: [AngularJS, webpack] hide_table_of_contents: false +description: '`raw-loader` package in webpack configuration for Angular 1.x projects preloads templates and enables compile-time error checking.' --- This technique actually applies to pretty much any web stack where you have to supply templates; it just so happens that I'm using Angular 1.x in this case. Also I have an extra technique which is useful to handle the [ng-include](https://docs.angularjs.org/api/ng/directive/ngInclude) scenario. diff --git a/blog-website/blog/2016-05-24-the-mysterious-case-of-webpack-angular-and-jquery/index.md b/blog-website/blog/2016-05-24-the-mysterious-case-of-webpack-angular-and-jquery/index.md index b82aac80ff8..c2235a4c0f3 100644 --- a/blog-website/blog/2016-05-24-the-mysterious-case-of-webpack-angular-and-jquery/index.md +++ b/blog-website/blog/2016-05-24-the-mysterious-case-of-webpack-angular-and-jquery/index.md @@ -4,6 +4,7 @@ title: 'The Mysterious Case of webpack, AngularJS and jQuery' authors: johnnyreilly tags: [jquery, AngularJS, webpack] hide_table_of_contents: false +description: 'Angular can use jQuery instead of jQLite, but this becomes complicated when using webpack. We need to use the ProvidePlugin function in webpack.config.js.' --- You may know that [Angular ships with a cutdown version of jQuery called jQLite](https://docs.angularjs.org/api/ng/function/angular.element). It's still possible to use the full-fat jQuery; to quote the docs: diff --git a/blog-website/blog/2016-06-02-create-es2015-map-from-array-in-typescript/index.md b/blog-website/blog/2016-06-02-create-es2015-map-from-array-in-typescript/index.md index 562fe6d97f5..630b1ef016d 100644 --- a/blog-website/blog/2016-06-02-create-es2015-map-from-array-in-typescript/index.md +++ b/blog-website/blog/2016-06-02-create-es2015-map-from-array-in-typescript/index.md @@ -4,6 +4,7 @@ title: 'Creating an ES2015 Map from an Array in TypeScript' authors: johnnyreilly tags: [typescript, ES6, ES2015] hide_table_of_contents: false +description: 'TypeScript `Map` initialization from an `Array` is discussed with a workaround using a type assertion of ` as [string, string]`.' --- I'm a great lover of ES2015's [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). However, just recently I tumbled over something I find a touch inconvenient about how you initialise a new `Map` from the contents of an `Array` in TypeScript. diff --git a/blog-website/blog/2016-08-19-the-ternary-operator-meets-destructuring/index.md b/blog-website/blog/2016-08-19-the-ternary-operator-meets-destructuring/index.md index 12892f22d27..ee4f0490745 100644 --- a/blog-website/blog/2016-08-19-the-ternary-operator-meets-destructuring/index.md +++ b/blog-website/blog/2016-08-19-the-ternary-operator-meets-destructuring/index.md @@ -4,6 +4,7 @@ title: 'The Ternary Operator <3 Destructuring' authors: johnnyreilly tags: [typescript, ES2015] hide_table_of_contents: false +description: 'ES2015 destructuring allows setting multiple variables using the ternary operator. Change the return type of each branch to an object for this to work.' --- I'm addicted to the [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator). For reasons I can't explain, I cannot get enough of: diff --git a/blog-website/blog/2016-09-12-integration-tests-with-sql-server/index.md b/blog-website/blog/2016-09-12-integration-tests-with-sql-server/index.md index 22c3e484370..8c2b5428b3a 100644 --- a/blog-website/blog/2016-09-12-integration-tests-with-sql-server/index.md +++ b/blog-website/blog/2016-09-12-integration-tests-with-sql-server/index.md @@ -4,6 +4,7 @@ title: 'Integration Tests with SQL Server Database Snapshots' authors: johnnyreilly tags: [Database Snapshots, Integration Testing, SQL Server] hide_table_of_contents: false +description: 'Discover the benefits of using database snapshots for integration tests to reduce complexity & errors in this informative article.' --- ## Once More With Feeling diff --git a/blog-website/blog/2016-09-22-typescript-20-es2016-and-babel/index.md b/blog-website/blog/2016-09-22-typescript-20-es2016-and-babel/index.md index 16a2d7c63b6..8a7593cec27 100644 --- a/blog-website/blog/2016-09-22-typescript-20-es2016-and-babel/index.md +++ b/blog-website/blog/2016-09-22-typescript-20-es2016-and-babel/index.md @@ -4,6 +4,7 @@ title: 'TypeScript 2.0, ES2016 and Babel' authors: johnnyreilly tags: [typescript, Babel, ES2016] hide_table_of_contents: false +description: 'Upgrading from ES2015 to ES2016 using TypeScript compiler and Babel can be done in a few steps, including a change to tsconfig.json.' --- [TypeScript 2.0 has shipped!](https://blogs.msdn.microsoft.com/typescript/2016/09/22/announcing-typescript-2-0/) Naturally I'm excited. For some time I've been using TypeScript to emit ES2015 code which I pass onto Babel to transpile to ES "old school". You can see how [here](../2015-12-16-es6-typescript-babel-react-flux-karma/index.md). @@ -37,9 +38,9 @@ Well, there's no `"es2016"` target for TypeScript. You carry on with a target of ## Babel changes -I needed the Babel preset for ES2016; with a quick [`npm install --save-dev babel-preset-es2016`](https://www.npmjs.com/package/babel-preset-es2016) that was sorted. Now just to kick Webpack into gear... +I needed the Babel preset for ES2016; with a quick [`npm install --save-dev babel-preset-es2016`](https://www.npmjs.com/package/babel-preset-es2016) that was sorted. Now just to kick webpack into gear... -## Webpack changes +## webpack changes My webpack config plugs together TypeScript and Babel with the help of [ts-loader](https://www.npmjs.com/package/ts-loader) and [babel-loader](https://www.npmjs.com/package/babel-loader). It allows the transpilation of my (few) JavaScript files so I can write ES2015. However, mainly it allows the transpilation of my (many) TypeScript files so I can write ES2015-flavoured TypeScript. I'll now tweak the `loaders` so they cater for ES2016 as well. diff --git a/blog-website/blog/2016-10-05-react-component-curry/index.md b/blog-website/blog/2016-10-05-react-component-curry/index.md index 04732edfa52..d0f06ea1469 100644 --- a/blog-website/blog/2016-10-05-react-component-curry/index.md +++ b/blog-website/blog/2016-10-05-react-component-curry/index.md @@ -4,6 +4,7 @@ title: 'React Component Curry' authors: johnnyreilly tags: [jsx, React, stateless functional components] hide_table_of_contents: false +description: 'React 0.14 introduces stateless functional components to reduce code for components where state isnt required, while also allowing for currying.' --- Everyone loves curry don't they? I don't know about you but I'm going for one on Friday. diff --git a/blog-website/blog/2016-11-01-but-you-cant-die-i-love-you-ts-loader/index.md b/blog-website/blog/2016-11-01-but-you-cant-die-i-love-you-ts-loader/index.md index 4dd1baa1ca3..aea1060fe32 100644 --- a/blog-website/blog/2016-11-01-but-you-cant-die-i-love-you-ts-loader/index.md +++ b/blog-website/blog/2016-11-01-but-you-cant-die-i-love-you-ts-loader/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [open source, typescript, ts-loader] image: ./title-image.png hide_table_of_contents: false +description: 'How John Reilly becomes main caretaker of ts-loader, fixing bugs and actively maintaining the project to encourage communal contributions.' --- That's how I was feeling on the morning of October 6th 2016. I'd been feeling that way for some time. The target of my concern? [ts-loader](https://github.com/TypeStrong/ts-loader). ts-loader is a loader for [webpack; the module bundler](https://webpack.github.io/). ts-loader allows you use TypeScript with webpack. I'd been a merry user of it for at least a year or so. But, at that point, all was not well in the land of ts-loader. Come with me and I'll tell you a story... diff --git a/blog-website/blog/2016-11-12-my-subconscious-is-better-developer/index.md b/blog-website/blog/2016-11-12-my-subconscious-is-better-developer/index.md index be0b9936e87..179338baea4 100644 --- a/blog-website/blog/2016-11-12-my-subconscious-is-better-developer/index.md +++ b/blog-website/blog/2016-11-12-my-subconscious-is-better-developer/index.md @@ -4,6 +4,7 @@ title: 'My Subconscious is a Better Developer Than I Am' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'In which I wonder if my subconscious is a better developer than I am, as solutions seem to come to mind, bypassing the work I consciously put in.' --- Occasionally I flatter myself that I'm alright at this development lark. Such egotistical talk is foolish. What makes me pause even more when I consider the proposition is this: my subconscious is a better developer than I am. diff --git a/blog-website/blog/2016-12-11-webpack-syncing-enhanced-resolve/index.md b/blog-website/blog/2016-12-11-webpack-syncing-enhanced-resolve/index.md index 8e13fa9b845..4090885bc83 100644 --- a/blog-website/blog/2016-12-11-webpack-syncing-enhanced-resolve/index.md +++ b/blog-website/blog/2016-12-11-webpack-syncing-enhanced-resolve/index.md @@ -4,6 +4,7 @@ title: 'webpack: syncing the enhanced-resolve' authors: johnnyreilly tags: [webpack] hide_table_of_contents: false +description: 'How to create a sync webpack resolver instead of the default async resolver using `enhanced-resolve`.' --- Like Captain Ahab I resolve to sync the white whale that is webpack's [`enhanced-resolve`](https://github.com/webpack/enhanced-resolve)... English you say? Let me start again: @@ -48,7 +49,7 @@ Put it all together and what have you got? const resolvedFileName = resolveSync( undefined, 'C:source\ts-loader.test\babel-issue92', - './submodule/submodule' + './submodule/submodule', ); // resolvedFileName: C:\source\ts-loader\.test\babel-issue92\submodule\submodule.tsx diff --git a/blog-website/blog/2016-12-19-using-ts-loader-with-webpack-2/index.md b/blog-website/blog/2016-12-19-using-ts-loader-with-webpack-2/index.md index 87fe2dc5a8a..0b7c9500fab 100644 --- a/blog-website/blog/2016-12-19-using-ts-loader-with-webpack-2/index.md +++ b/blog-website/blog/2016-12-19-using-ts-loader-with-webpack-2/index.md @@ -4,6 +4,7 @@ title: 'Using ts-loader with webpack 2' authors: johnnyreilly tags: [ts-loader, webpack] hide_table_of_contents: false +description: 'TypeScript loader ts-loader has made its loader compatible with webpack 2. The update allows greater compatibility between the two applications.' --- Hands up, despite being one of the maintainers of [ts-loader](https://github.com/TypeStrong/ts-loader) (a TypeScript loader for webpack) I have not been tracking webpack v2. My reasons? Well, I'm keen on cutting edge but bleeding edge is often not a ton of fun as dealing with regularly breaking changes is frustrating. I'm generally happy to wait for things to settle down a bit before leaping aboard. However, [webpack 2 RC'd last week](https://github.com/webpack/webpack/releases/tag/v2.2.0-rc.0) and so it's time to take a look! @@ -179,7 +180,7 @@ function buildProduction(done) { debug: false, }), - failPlugin + failPlugin, ); // ..... @@ -196,15 +197,15 @@ function createDevCompiler() { filename: 'vendor.js', }), new WebpackNotifierPlugin({ - title: 'Webpack build', + title: 'webpack build', excludeWarnings: true, }), - // this is the Webpack 2 hotness! + // this is the webpack 2 hotness! new webpack.LoaderOptionsPlugin({ debug: true, options: myDevConfig, - }) + }), // it ends here - there wasn't much really.... ); @@ -232,7 +233,7 @@ function buildProduction(done) { }, }), - failPlugin + failPlugin, ); // ..... @@ -247,7 +248,10 @@ function createDevCompiler() { name: 'vendor', filename: 'vendor.js', }), - new WebpackNotifierPlugin({ title: 'Webpack build', excludeWarnings: true }) + new WebpackNotifierPlugin({ + title: 'webpack build', + excludeWarnings: true, + }), ); // create a single instance of the compiler to allow caching diff --git a/blog-website/blog/2017-01-01-webpack-configuring-loader-with-query/index.md b/blog-website/blog/2017-01-01-webpack-configuring-loader-with-query/index.md index ba7f046623f..c801ed6d50f 100644 --- a/blog-website/blog/2017-01-01-webpack-configuring-loader-with-query/index.md +++ b/blog-website/blog/2017-01-01-webpack-configuring-loader-with-query/index.md @@ -4,6 +4,7 @@ title: 'webpack: configuring a loader with query / options' authors: johnnyreilly tags: [webpack] hide_table_of_contents: false +description: 'webpack 2 now enforces a strict schema for `webpack.config.js`. Loaders should be configured using `query` or `options`.' --- [webpack 2 is on it's way](https://medium.com/webpack/webpack-2-2-the-release-candidate-2e614d05d75f#.ntniu44u6). As one of the maintainers of [ts-loader](https://github.com/TypeStrong/ts-loader/) I've been checking out that ts-loader works with webpack 2. It does: phew! diff --git a/blog-website/blog/2017-01-06-webpack-resolveloader-alias-with-query/index.md b/blog-website/blog/2017-01-06-webpack-resolveloader-alias-with-query/index.md index 3328b626e2b..44a4dc16d48 100644 --- a/blog-website/blog/2017-01-06-webpack-resolveloader-alias-with-query/index.md +++ b/blog-website/blog/2017-01-06-webpack-resolveloader-alias-with-query/index.md @@ -4,6 +4,7 @@ title: 'webpack: resolveLoader / alias with query / options' authors: johnnyreilly tags: [webpack] hide_table_of_contents: false +description: 'Webpacks enhanced-resolve has a bug with aliased loaders. A workaround involves suffixing the aliased path with query options.' --- Sometimes you write a post for the ages. Sometimes you write one you hope is out of date before you hit "publish". This is one of those. @@ -57,7 +58,7 @@ rules.forEach(function (rule) { var options = rule.query || rule.options; rule.loader = rule.loader.replace( 'ts-loader', - loaderAliasPath + (options ? '?' + JSON.stringify(options) : '') + loaderAliasPath + (options ? '?' + JSON.stringify(options) : ''), ); }); ``` diff --git a/blog-website/blog/2017-02-01-hands-free-https/index.md b/blog-website/blog/2017-02-01-hands-free-https/index.md index 4d41bc271d1..2d1b5c551b7 100644 --- a/blog-website/blog/2017-02-01-hands-free-https/index.md +++ b/blog-website/blog/2017-02-01-hands-free-https/index.md @@ -4,6 +4,7 @@ title: 'Hands-free HTTPS' authors: johnnyreilly tags: [TLS, HTTPS, cloudflare] hide_table_of_contents: false +description: 'CloudFlare provides free HTTPS certificates. As HTTPS becomes the web default, it is essential for search engine ranking and service workers.' --- I have had a \***great**\* week. You? Take a look at this blog. Can you see what I can see? Here's a clue: diff --git a/blog-website/blog/2017-02-14-typescript-types-and-repeatable-builds/index.md b/blog-website/blog/2017-02-14-typescript-types-and-repeatable-builds/index.md index 73904d2b8cb..20ede1f85cb 100644 --- a/blog-website/blog/2017-02-14-typescript-types-and-repeatable-builds/index.md +++ b/blog-website/blog/2017-02-14-typescript-types-and-repeatable-builds/index.md @@ -4,6 +4,7 @@ title: '@types is rogue' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'Type definitions from Definitely Typed under @types namespace on npm cannot be trusted to follow semantic versioning, leading to breakages.' --- Or perhaps I should call this "@types and repeatable builds".... diff --git a/blog-website/blog/2017-02-23-under-duck-afternoon-in-open-source/index.md b/blog-website/blog/2017-02-23-under-duck-afternoon-in-open-source/index.md index b5779374549..3cfc8971e48 100644 --- a/blog-website/blog/2017-02-23-under-duck-afternoon-in-open-source/index.md +++ b/blog-website/blog/2017-02-23-under-duck-afternoon-in-open-source/index.md @@ -4,6 +4,7 @@ title: 'Under the Duck: An Afternoon in Open Source' authors: johnnyreilly tags: [ts-loader, webpack] hide_table_of_contents: false +description: 'A minute-by-minute account of how open source developers fixed an issue with ts-loader and webpack, demonstrating the collaborative nature of the community.' --- Have you ever wondered what happens behind the scenes of open source projects? One that I'm involved with is [ts-loader](https://github.com/typestrong/ts-loader); a TypeScript loader for webpack. Yesterday was an interesting day in the life of ts-loader and webpack; things unexpectedly broke. Oh and don't worry, they're fixed now. diff --git a/blog-website/blog/2017-03-28-debugging-aspnet-core-in-vs-or-code/index.md b/blog-website/blog/2017-03-28-debugging-aspnet-core-in-vs-or-code/index.md index c4c0b17775f..685c3c93ce3 100644 --- a/blog-website/blog/2017-03-28-debugging-aspnet-core-in-vs-or-code/index.md +++ b/blog-website/blog/2017-03-28-debugging-aspnet-core-in-vs-or-code/index.md @@ -4,6 +4,7 @@ title: 'Debugging ASP.Net Core in VS or Code' authors: johnnyreilly tags: [VS Code, ASP.Net Core, Visual Studio] hide_table_of_contents: false +description: 'Learn how John became a fan of VS Code for TypeScript and how they managed to debug ASP.Net Core using the extension for C#.' --- I've been using Visual Studio for a long time. Very good it is too. However, it is heavyweight; it does far more than I need. What I really want when I'm working is a fast snappy editor, with intellisense and debugging. What I've basically described is [VS Code](https://code.visualstudio.com/). It rocks and has long become my go-to editor for TypeScript. diff --git a/blog-website/blog/2017-03-30-im-looking-for-work/index.md b/blog-website/blog/2017-03-30-im-looking-for-work/index.md index 8abe6fb623b..e7a84eb57fa 100644 --- a/blog-website/blog/2017-03-30-im-looking-for-work/index.md +++ b/blog-website/blog/2017-03-30-im-looking-for-work/index.md @@ -4,6 +4,7 @@ title: "I'm looking for work!" authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'Full stack developer John Reilly seeks new work after finishing recent contract. 15 years’ experience includes telecoms, advertising, tech and finance.' --- My name is John Reilly. I'm a full stack developer based in London, UK. I'm just coming to the end of a contract (due to finish in April 2017) and I'm starting to look for my next role. diff --git a/blog-website/blog/2017-04-25-setting-build-version-using-appveyor/index.md b/blog-website/blog/2017-04-25-setting-build-version-using-appveyor/index.md index 22c850bd181..5a8df2cf1e0 100644 --- a/blog-website/blog/2017-04-25-setting-build-version-using-appveyor/index.md +++ b/blog-website/blog/2017-04-25-setting-build-version-using-appveyor/index.md @@ -4,6 +4,7 @@ title: 'Setting Build Version Using AppVeyor and ASP.Net Core' authors: johnnyreilly tags: [powershell, Version, dot net core, AppVeyor] hide_table_of_contents: false +description: 'AppVeyor doesnt have support for setting version of a binary in dot net core, but it can be done easily through PowerShell.' --- AppVeyor has [support for setting the version of a binary during a build](https://www.appveyor.com/docs/build-configuration/#assemblyinfo-patching). However - this deals with the classic ASP.Net world of `AssemblyInfo`. I didn't find any reference to support for doing the same with dot net core. Remember, dot net core [relies upon a `<Version>` or a `<VersionPrefix>` setting in the `.csproj` file](https://docs.microsoft.com/en-us/dotnet/articles/core/tools/project-json-to-csproj#version). Personally, `<Version>` is my jam. diff --git a/blog-website/blog/2017-05-20-typescript-spare-rod-spoil-code/index.md b/blog-website/blog/2017-05-20-typescript-spare-rod-spoil-code/index.md index 62aa837663b..a1b9b54982b 100644 --- a/blog-website/blog/2017-05-20-typescript-spare-rod-spoil-code/index.md +++ b/blog-website/blog/2017-05-20-typescript-spare-rod-spoil-code/index.md @@ -4,6 +4,7 @@ title: 'TypeScript: Spare the Rod, Spoil the Code' authors: johnnyreilly tags: [tsconfig.json, typescript] hide_table_of_contents: false +description: 'TypeScript settings catch bugs. Use compiler options to increase strictness gradually & catch errors such as unused variables with VS Code.' --- I've recently started a new role. Perhaps unsurprisingly, part of the technology stack is TypeScript. A couple of days into the new codebase I found a bug. Well, I say I found a bug, TypeScript and VS Code found the bug - I just let everyone else know. diff --git a/blog-website/blog/2017-06-11-windows-defender-step-away-from-npm/index.md b/blog-website/blog/2017-06-11-windows-defender-step-away-from-npm/index.md index d46cd0ca4d9..40b4dcb35a3 100644 --- a/blog-website/blog/2017-06-11-windows-defender-step-away-from-npm/index.md +++ b/blog-website/blog/2017-06-11-windows-defender-step-away-from-npm/index.md @@ -4,6 +4,7 @@ title: 'Windows Defender Step Away From npm' authors: johnnyreilly tags: [VS Code, Windows, npm] hide_table_of_contents: false +description: 'A bug causing issues with Windows Defender has been fixed with the release of VS Code 1.14. The bug was causing problems with the program open.' --- ## Updated 18/06/2017 @@ -16,8 +17,6 @@ The issue was VS Code. The bug has now been fixed and shipped last night with [V ---- - I've recently experienced many of my `npm install`s failing for no consistent reason. The error message would generally be something along the lines of: ```sh diff --git a/blog-website/blog/2017-07-02-dynamic-import-ive-been-await-ing-you/index.md b/blog-website/blog/2017-07-02-dynamic-import-ive-been-await-ing-you/index.md index c087591c4ff..283d24caca2 100644 --- a/blog-website/blog/2017-07-02-dynamic-import-ive-been-await-ing-you/index.md +++ b/blog-website/blog/2017-07-02-dynamic-import-ive-been-await-ing-you/index.md @@ -4,6 +4,7 @@ title: "Dynamic import: I've been awaiting you..." authors: johnnyreilly tags: [typescript, webpack] hide_table_of_contents: false +description: 'TypeScript 2.4 gains asynchronous, dynamic import expression for modules with no browser support. Webpack2 supports this feature.' --- One of the most exciting features to ship with TypeScript 2.4 was support for the dynamic import expression. To quote the [release blog post](https://blogs.msdn.microsoft.com/typescript/2017/06/27/announcing-typescript-2-4/#dynamic-import-expressions): diff --git a/blog-website/blog/2017-07-29-a-haiku-on-problem-with-semver-us/index.md b/blog-website/blog/2017-07-29-a-haiku-on-problem-with-semver-us/index.md index 5ef3af4180a..23e84440fb4 100644 --- a/blog-website/blog/2017-07-29-a-haiku-on-problem-with-semver-us/index.md +++ b/blog-website/blog/2017-07-29-a-haiku-on-problem-with-semver-us/index.md @@ -4,6 +4,7 @@ title: 'A Haiku on the Problem with SemVer: Us' authors: johnnyreilly tags: [semantic versioning] hide_table_of_contents: false +description: 'A Haiku on the Problem with SemVer: Us' --- Version numbers wrong diff --git a/blog-website/blog/2017-08-27-karma-from-phantomjs-to-headless-chrome/index.md b/blog-website/blog/2017-08-27-karma-from-phantomjs-to-headless-chrome/index.md index c60473f4635..0b81b1864bc 100644 --- a/blog-website/blog/2017-08-27-karma-from-phantomjs-to-headless-chrome/index.md +++ b/blog-website/blog/2017-08-27-karma-from-phantomjs-to-headless-chrome/index.md @@ -4,6 +4,7 @@ title: 'Karma: From PhantomJS to Headless Chrome' authors: johnnyreilly tags: [Chrome, Karma, PhantomJS] hide_table_of_contents: false +description: 'Replace PhantomJS with new Chrome Headless to run Chrome without a UI. Migrate a test and add Chrome to your build environment.' --- Like pretty much everyone else I've been using PhantomJS to run my JavaScript (or compiled-to-JS) unit tests. It's been great. So when I heard the news that [PhantomJS was dead](https://news.ycombinator.com/item?id=14105489) I was genuinely sad. However, the King is dead.... Long live the King! For there is a new hope; it's called [Chrome Headless ](https://developers.google.com/web/updates/2017/04/headless-chrome). It's not a separate version of Chrome; rather the ability to run Chrome without a UI is now baked into Google's favourite browser as of v59. (For those history buffs I might as well be clear: the main reason PhantomJS died is because Chrome Headless was in the works.) diff --git a/blog-website/blog/2017-08-30-oh-glamour-of-open-source/index.md b/blog-website/blog/2017-08-30-oh-glamour-of-open-source/index.md index 8c39c707a98..40db8574f2e 100644 --- a/blog-website/blog/2017-08-30-oh-glamour-of-open-source/index.md +++ b/blog-website/blog/2017-08-30-oh-glamour-of-open-source/index.md @@ -4,6 +4,7 @@ title: 'Oh the Glamour of Open Source' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'A programmer recounts a sleepless night spent fixing a gap in an open source project, but accidentally deletes the repo and eventually seeks help.' --- Here's how my life panned out in the early hours of Wednesday 30th September 2017: diff --git a/blog-website/blog/2017-09-07-typescript-webpack-super-pursuit-mode/index.md b/blog-website/blog/2017-09-07-typescript-webpack-super-pursuit-mode/index.md index a345523e577..6ffe0f0d3ef 100644 --- a/blog-website/blog/2017-09-07-typescript-webpack-super-pursuit-mode/index.md +++ b/blog-website/blog/2017-09-07-typescript-webpack-super-pursuit-mode/index.md @@ -1,9 +1,10 @@ --- slug: typescript-webpack-super-pursuit-mode -title: 'TypeScript + Webpack: Super Pursuit Mode' +title: 'TypeScript + webpack: Super Pursuit Mode' authors: johnnyreilly -tags: [typescript, fork-ts-checker-webpack-plugin, Webpack] +tags: [typescript, fork-ts-checker-webpack-plugin, webpack] hide_table_of_contents: false +description: 'Learn how to improve build speeds with TypeScript and webpack using fork-ts-checker-webpack-plugin, HappyPack, and thread-loader/cache-loader.' --- _[This post also featured as a webpack Medium publication](https://medium.com/webpack/typescript-webpack-super-pursuit-mode-83cc568dea79)._ @@ -26,7 +27,7 @@ Apologies for the image quality above; there appear to be no high quality pictur ["Faster type checking with forked process"](https://github.com/TypeStrong/ts-loader/issues/537) read the enticing name of the issue. It turned out to be [Piotr Oleś](https://github.com/piotr-oles) ([@OlesDev](https://twitter.com/OlesDev)) telling the world about his beautiful creation. He'd put together a mighty fine plugin that can be used alongside ts-loader called the [fork-ts-checker-webpack-plugin](https://github.com/Realytics/fork-ts-checker-webpack-plugin). The name is a bit of a mouthful but the purpose is mouth-watering. To quote the README, it is a: -> Webpack plugin that runs typescript type checker on a separate process. +> webpack plugin that runs typescript type checker on a separate process. What does this mean and how does this fit with ts-loader? Well, ts-loader does 2 jobs: diff --git a/blog-website/blog/2017-09-12-fork-ts-checker-webpack-plugin-code/index.md b/blog-website/blog/2017-09-12-fork-ts-checker-webpack-plugin-code/index.md index 4d45d35e724..38510fd50b3 100644 --- a/blog-website/blog/2017-09-12-fork-ts-checker-webpack-plugin-code/index.md +++ b/blog-website/blog/2017-09-12-fork-ts-checker-webpack-plugin-code/index.md @@ -4,6 +4,7 @@ title: 'fork-ts-checker-webpack-plugin code clickability' authors: johnnyreilly tags: [VS Code, fork-ts-checker-webpack-plugin, ts-loader, webpack] hide_table_of_contents: false +description: 'The `fork-ts-checker-webpack-plugin` can speed up builds, but TypeScript errors in the terminal are not clickable. The cause and solution are explained.' --- My name is John Reilly and I'm a VS Code addict. There I said it. I'm also a big fan of TypeScript and webpack. I've recently switched to using the awesome [`fork-ts-checker-webpack-plugin`](https://www.npmjs.com/package/fork-ts-checker-webpack-plugin) to speed up my builds. @@ -41,7 +42,7 @@ function clickableFormatter(message, useColors) { message.getLine() + ',' + message.getCharacter() + - ')' + ')', ) + messageColor(':'), diff --git a/blog-website/blog/2017-10-19-working-with-extrahop-on-webpack-and-ts/index.md b/blog-website/blog/2017-10-19-working-with-extrahop-on-webpack-and-ts/index.md index ba93d59eb2d..6a2847dc021 100644 --- a/blog-website/blog/2017-10-19-working-with-extrahop-on-webpack-and-ts/index.md +++ b/blog-website/blog/2017-10-19-working-with-extrahop-on-webpack-and-ts/index.md @@ -4,6 +4,7 @@ title: 'Working with Extrahop on webpack and ts-loader' authors: johnnyreilly tags: [ts-loader, webpack] hide_table_of_contents: false +description: 'John shares his excitement for working with talented individuals on open source software - its everywhere and a privilege to work on.' --- I'm quite proud of this: [https://www.extrahop.com/company/blog/2017/extrahop-webpack-accelerating-build-times/](https://www.extrahop.com/company/blog/2017/extrahop-webpack-accelerating-build-times/) diff --git a/blog-website/blog/2017-10-20-typescript-definitions-webpack-and-module-types/index.md b/blog-website/blog/2017-10-20-typescript-definitions-webpack-and-module-types/index.md index 88f80a1f6e1..006fb6d52e5 100644 --- a/blog-website/blog/2017-10-20-typescript-definitions-webpack-and-module-types/index.md +++ b/blog-website/blog/2017-10-20-typescript-definitions-webpack-and-module-types/index.md @@ -4,6 +4,7 @@ title: 'TypeScript Definitions, webpack and Module Types' authors: johnnyreilly tags: [Definitely Typed, typescript, webpack] hide_table_of_contents: false +description: 'Inconsistent module exports cause confusion while using the npm package big.js, leading to `one definition to rule them all.`' --- A funny thing happened on the way to the registry the other day. Something changed in an npm package I was using and confusion arose. You can read my unfiltered confusion [here](https://github.com/Microsoft/TypeScript/issues/18791) but here's the slightly clearer explanation. diff --git a/blog-website/blog/2017-11-19-the-typescript-webpack-pwa/index.md b/blog-website/blog/2017-11-19-the-typescript-webpack-pwa/index.md index 3fb6de8370e..fc67b437afe 100644 --- a/blog-website/blog/2017-11-19-the-typescript-webpack-pwa/index.md +++ b/blog-website/blog/2017-11-19-the-typescript-webpack-pwa/index.md @@ -4,6 +4,7 @@ title: 'The TypeScript webpack PWA' authors: johnnyreilly tags: [typescript, PWA, webpack] hide_table_of_contents: false +description: 'Learn how to turn a TypeScript, webpack setup into a PWA using Workbox. With service workers, build offline-capable web apps.' --- So, there you sit, conflicted. You've got a lovely build setup; it's a thing of beauty. Precious, polished like a diamond, sharpened like a circular saw. There at the core of your carefully crafted setup sits webpack. Heaving, mysterious... powerful. diff --git a/blog-website/blog/2017-12-24-ts-loader-2017-retrospective/index.md b/blog-website/blog/2017-12-24-ts-loader-2017-retrospective/index.md index 7db18ce505f..7750c54c567 100644 --- a/blog-website/blog/2017-12-24-ts-loader-2017-retrospective/index.md +++ b/blog-website/blog/2017-12-24-ts-loader-2017-retrospective/index.md @@ -4,6 +4,7 @@ title: 'ts-loader 2017 retrospective' authors: johnnyreilly tags: [typescript, ts-loader, webpack] hide_table_of_contents: false +description: 'ts-loader has improved in 2017, now sitting at v3.2.0 and supporting webpack 2 and 3. Future plans include using the new watch API.' --- 2017 is drawing to a close, and it's been a big, big year in webpack-land. It's been a big year for `ts-loader` too. At the start of the year v1.3.3 was the latest version available, officially supporting webpack 1. (Old school!) We end the year with `ts-loader` sitting pretty at v3.2.0 and supporting webpack 2 and 3. diff --git a/blog-website/blog/2018-01-14-auth0-typescript-and-aspnet-core/index.md b/blog-website/blog/2018-01-14-auth0-typescript-and-aspnet-core/index.md index 34db0ee1169..cedd55c7518 100644 --- a/blog-website/blog/2018-01-14-auth0-typescript-and-aspnet-core/index.md +++ b/blog-website/blog/2018-01-14-auth0-typescript-and-aspnet-core/index.md @@ -4,6 +4,7 @@ title: 'Auth0, TypeScript and ASP.NET Core' authors: johnnyreilly tags: [ASP.Net Core, Auth0, typescript, OAuth, React] hide_table_of_contents: false +description: 'Auth0 makes authentication and authorization simple. They offer Auth-As-A-Service, quick start and easy customization of settings.' --- Most applications I write have some need for authentication and perhaps authorisation too. In fact, most apps most people write fall into that bracket. Here's the thing: Auth done well is a \*big\* chunk of work. And the minute you start thinking about that you almost invariably lose focus on the thing you actually want to build and ship. @@ -93,7 +94,10 @@ export class AuthStore { @observable.ref userProfile: Auth0UserProfile; @observable.ref token: IStorageToken; - constructor(config: IAuth0Config, private storage: StorageFacade) { + constructor( + config: IAuth0Config, + private storage: StorageFacade, + ) { this.auth0 = new WebAuth({ domain: config.domain, clientID: config.clientId, diff --git a/blog-website/blog/2018-01-28-webpack-4-ts-loader-fork-ts-checker/index.md b/blog-website/blog/2018-01-28-webpack-4-ts-loader-fork-ts-checker/index.md index 93f63d37c64..5bf083da8de 100644 --- a/blog-website/blog/2018-01-28-webpack-4-ts-loader-fork-ts-checker/index.md +++ b/blog-website/blog/2018-01-28-webpack-4-ts-loader-fork-ts-checker/index.md @@ -2,8 +2,9 @@ slug: webpack-4-ts-loader-fork-ts-checker title: 'webpack 4 - ts-loader / fork-ts-checker-webpack-plugin betas' authors: johnnyreilly -tags: [fork-ts-checker-webpack-plugin, ts-loader, Webpack] +tags: [fork-ts-checker-webpack-plugin, ts-loader, webpack] hide_table_of_contents: false +description: 'The TypeScript ts-loader beta to work with webpack 4 is now available, along with the fork-ts-checker-webpack-plugin, which complements ts-loader.' --- [The first webpack 4 beta dropped on Friday](https://medium.com/webpack/webpack-4-beta-try-it-today-6b1d27d7d7e2). Very exciting! Following hot on the heels of those announcements, I've some news to share too. Can you guess what it is? diff --git a/blog-website/blog/2018-01-29-finding-webpack-4-use-map/index.md b/blog-website/blog/2018-01-29-finding-webpack-4-use-map/index.md index c74921decf4..4d000ef1ad2 100644 --- a/blog-website/blog/2018-01-29-finding-webpack-4-use-map/index.md +++ b/blog-website/blog/2018-01-29-finding-webpack-4-use-map/index.md @@ -4,6 +4,7 @@ title: 'Finding webpack 4 (use a Map)' authors: johnnyreilly tags: [webpack] hide_table_of_contents: false +description: 'webpack 4s new plugin architecture requires migrating from "kebab-case" to "camelCase". A migration guide for plugins and loaders is available.' --- ## Update: 03/02/2018 @@ -37,7 +38,7 @@ this.compiler.hooks.watchClose.tap( 'name-to-identify-your-plugin-goes-here', () => { // do your thing here - } + }, ); ``` @@ -60,7 +61,7 @@ this.compiler.hooks.watchRun.tapAsync( (compiler, callback) => { // do your thing here callback(); - } + }, ); ``` @@ -141,7 +142,7 @@ With webpack 4 these become: ```js loader._compiler.hooks.afterCompile.tapAsync( - 'ts-loader' /* callback goes here */ + 'ts-loader' /* callback goes here */, ); loader._compiler.hooks.watchRun.tapAsync('ts-loader' /* callback goes here */); ``` @@ -162,7 +163,7 @@ What this means is, code that would once have looked like this: Object.keys(watching.compiler.fileTimestamps) .filter( (filePath) => - watching.compiler.fileTimestamps[filePath] > lastTimes[filePath] + watching.compiler.fileTimestamps[filePath] > lastTimes[filePath], ) .forEach((filePath) => { lastTimes[filePath] = times[filePath]; diff --git a/blog-website/blog/2018-02-25-ts-loader-400-fork-ts-checker-webpack/index.md b/blog-website/blog/2018-02-25-ts-loader-400-fork-ts-checker-webpack/index.md index 607538017bd..ebd789bdd5f 100644 --- a/blog-website/blog/2018-02-25-ts-loader-400-fork-ts-checker-webpack/index.md +++ b/blog-website/blog/2018-02-25-ts-loader-400-fork-ts-checker-webpack/index.md @@ -4,6 +4,7 @@ title: 'ts-loader 4 / fork-ts-checker-webpack-plugin 0.4' authors: johnnyreilly tags: [webpack, fork-ts-checker-webpack-plugin, ts-loader] hide_table_of_contents: false +description: 'webpack 4 has been released, along with updates for ts-loader and fork-ts-checker-webpack-plugin. See links for details and examples.' --- webpack 4 has shipped! diff --git a/blog-website/blog/2018-03-07-its-not-dead-webpack-and-dead-code/index.md b/blog-website/blog/2018-03-07-its-not-dead-webpack-and-dead-code/index.md index a29c5f39302..1cafa81cb83 100644 --- a/blog-website/blog/2018-03-07-its-not-dead-webpack-and-dead-code/index.md +++ b/blog-website/blog/2018-03-07-its-not-dead-webpack-and-dead-code/index.md @@ -4,9 +4,10 @@ title: "It's Not Dead: webpack and dead code elimination limitations" authors: johnnyreilly tags: [webpack] hide_table_of_contents: false +description: 'webpack eliminates dead code through DefinePlugin. Directly use `process.env.NODE_ENV !== production` for smarter code elimination by UglifyJSPlugin.' --- -Webpack has long supported the notion of dead code elimination. webpack facilitates this through use of the `DefinePlugin`. The compile time value of `process.env.NODE_ENV` is set either to `'production'` or something else. If it's set to `'production'` then some dead code hackery can happen. [Libraries like React make use of this to serve up different, and crucially smaller, production builds.](https://reactjs.org/docs/optimizing-performance.html#webpack) +webpack has long supported the notion of dead code elimination. webpack facilitates this through use of the `DefinePlugin`. The compile time value of `process.env.NODE_ENV` is set either to `'production'` or something else. If it's set to `'production'` then some dead code hackery can happen. [Libraries like React make use of this to serve up different, and crucially smaller, production builds.](https://reactjs.org/docs/optimizing-performance.html#webpack) diff --git a/blog-website/blog/2018-03-25-uploading-images-to-cloudinary-with-fetch/index.md b/blog-website/blog/2018-03-25-uploading-images-to-cloudinary-with-fetch/index.md index 642bb3ad7da..f1b0bfbb82e 100644 --- a/blog-website/blog/2018-03-25-uploading-images-to-cloudinary-with-fetch/index.md +++ b/blog-website/blog/2018-03-25-uploading-images-to-cloudinary-with-fetch/index.md @@ -4,6 +4,7 @@ title: 'Uploading Images to Cloudinary with the Fetch API' authors: johnnyreilly tags: [React, Cloudinary] hide_table_of_contents: false +description: 'Learn how to handle image uploads to Cloudinary using Fetch instead of SuperAgent with a sample code demonstrating the replacement of FormData.' --- I was recently checking out a [very good post](https://css-tricks.com/image-upload-manipulation-react/) which explained how to upload images using [React Dropzone](https://github.com/react-dropzone/react-dropzone) and [SuperAgent](https://github.com/visionmedia/superagent) to [Cloudinary](https://cloudinary.com/). diff --git a/blog-website/blog/2018-03-26-its-not-dead-2-mobx-react-devtools-and-the-undead/index.md b/blog-website/blog/2018-03-26-its-not-dead-2-mobx-react-devtools-and-the-undead/index.md index 6a598c6f99f..c852a4b9bda 100644 --- a/blog-website/blog/2018-03-26-its-not-dead-2-mobx-react-devtools-and-the-undead/index.md +++ b/blog-website/blog/2018-03-26-its-not-dead-2-mobx-react-devtools-and-the-undead/index.md @@ -4,6 +4,7 @@ title: "It's Not Dead 2: mobx-react-devtools and the undead" authors: johnnyreilly tags: [uglifyjs, mobx, webpack] hide_table_of_contents: false +description: 'Using `mobx-react-devtools` with `process.env.NODE_ENV` caused problems with webpack production mode. A different approach fixed the issue.' --- I spent today digging through our webpack 4 config trying to work out why a production bundle contained code like this: diff --git a/blog-website/blog/2018-04-28-using-reflection-to-identify-unwanted-dependencies/index.md b/blog-website/blog/2018-04-28-using-reflection-to-identify-unwanted-dependencies/index.md index c44186c09b8..bae95269e80 100644 --- a/blog-website/blog/2018-04-28-using-reflection-to-identify-unwanted-dependencies/index.md +++ b/blog-website/blog/2018-04-28-using-reflection-to-identify-unwanted-dependencies/index.md @@ -4,6 +4,7 @@ title: 'Using Reflection to Identify Unwanted Dependencies' authors: johnnyreilly tags: [.NET] hide_table_of_contents: false +description: 'Learn how to identify unwelcome dependencies in complex web apps by walking a dependency tree using reflection-based tests.' --- I having a web app which is fairly complex. It's made up of services, controllers and all sorts of things. So far, so unremarkable. However, I needed to ensure that the controllers did not attempt to access the database via any of their dependencies. Or their dependencies, dependencies. Or their dependencies. You get my point. diff --git a/blog-website/blog/2018-05-13-compromising-guide-for-developers/index.md b/blog-website/blog/2018-05-13-compromising-guide-for-developers/index.md index 49d8cbdd4dd..3f728745fa9 100644 --- a/blog-website/blog/2018-05-13-compromising-guide-for-developers/index.md +++ b/blog-website/blog/2018-05-13-compromising-guide-for-developers/index.md @@ -3,6 +3,7 @@ slug: compromising-guide-for-developers title: 'Compromising: A Guide for Developers' authors: johnnyreilly hide_table_of_contents: false +description: 'Weighing opinions with a voting system can reduce friction and boost productivity when working with developers of different opinions.' --- It is a truth universally acknowledged, that a single developer, will not be short of an opinion. Opinions on tabs vs spaces. Upon OOP vs FP. Upon `class`es vs `function`s. Just opinions, opinions, opinions. Opinions that are felt with all the sincerity of a Witchfinder General. And, alas, not always the same level of empathy. diff --git a/blog-website/blog/2018-06-16-vsts-yaml-up/index.md b/blog-website/blog/2018-06-16-vsts-yaml-up/index.md index 35660b92b14..fe4ac91c42e 100644 --- a/blog-website/blog/2018-06-16-vsts-yaml-up/index.md +++ b/blog-website/blog/2018-06-16-vsts-yaml-up/index.md @@ -4,6 +4,7 @@ title: 'VSTS... YAML up!' authors: johnnyreilly tags: [yaml, vsts, travis, AppVeyor] hide_table_of_contents: false +description: 'Visual Studio Team Services now has a YAML build definition preview feature that enables users to keep their build scripts with their code.' --- For the longest time I've been using the likes of [Travis](https://travis-ci.org/) and [AppVeyor](https://www.appveyor.com/) to build open source projects that I work on. They rock. I've also recently been dipping my toes back in the water of [Visual Studio Team Services](https://www.visualstudio.com/team-services/). VSTS offers a whole stack of stuff, but my own area of interest has been the Continuous Integration / Continuous Deployment offering. diff --git a/blog-website/blog/2018-06-24-vsts-and-ef-core-migrations/index.md b/blog-website/blog/2018-06-24-vsts-and-ef-core-migrations/index.md index ee9b4dcd088..fa93ff2d500 100644 --- a/blog-website/blog/2018-06-24-vsts-and-ef-core-migrations/index.md +++ b/blog-website/blog/2018-06-24-vsts-and-ef-core-migrations/index.md @@ -4,6 +4,7 @@ title: 'VSTS and EF Core Migrations' authors: johnnyreilly tags: [vsts, Entity Framework] hide_table_of_contents: false +description: 'Learn how to migrate Entity Framework database migrations during an ASP.NET Core project deployment with a console app using VSTS and Azure.' --- Let me start by telling you a dirty secret. I have an ASP.Net Core project that I build with VSTS. It is deployed to Azure through a CI / CD setup in VSTS. That part I'm happy with. Proud of even. Now to the sordid hiddenness: try as I might, I've never found a nice way to deploy Entity Framework database migrations as part of the deployment flow. So I have [blushes with embarrassment] been using the `Startup` of my ASP.Net core app to run the migrations on my database. There. I said it. You all know. Absolutely filthy. Don't judge me. diff --git a/blog-website/blog/2018-07-09-cypress-and-auth0/index.md b/blog-website/blog/2018-07-09-cypress-and-auth0/index.md index dc5a866cc49..e0eaec305c3 100644 --- a/blog-website/blog/2018-07-09-cypress-and-auth0/index.md +++ b/blog-website/blog/2018-07-09-cypress-and-auth0/index.md @@ -4,6 +4,7 @@ title: 'Cypress and Auth0' authors: johnnyreilly tags: [auth0-js, Auth0, cypress, auth] hide_table_of_contents: false +description: 'The article explains how to automate Auth0 login using Cypress, by using the auth0-js client library, and creating a custom command.' --- [Cypress](https://www.cypress.io/) is a fantastic way to write UI tests for your web apps. Just world class. Wait, no. Galaxy class. I'm going to go one further: universe class. You get my drift. @@ -70,13 +71,13 @@ Cypress.Commands.add('loginAsAdmin', (overrides = {}) => { window.sessionStorage.setItem( 'my-super-duper-app:storage_token', - JSON.stringify(token) + JSON.stringify(token), ); } else { console.error('Problem logging into Auth0', err); throw err; } - } + }, ); }); ``` @@ -128,6 +129,6 @@ You now have a test which automates your Auth0 login using Cypress and goes on t ## One More Thing... -It's worth saying that it's worth setting up different tenants in Auth0 to support your testing scenarios. This is generally a good idea so you can separate your testing accounts from Production accounts. Further to that, you don't need to have your Production setup supporting the ` Password``Grant Type `. +It's worth saying that it's worth setting up different tenants in Auth0 to support your testing scenarios. This is generally a good idea so you can separate your testing accounts from Production accounts. Further to that, you don't need to have your Production setup supporting the `Password``Grant Type`. Also, if you're curious about what the application under test is like then read [this](../2018-01-14-auth0-typescript-and-aspnet-core/index.md). diff --git a/blog-website/blog/2018-07-28-azure-app-service-web-app-containers-asp-net-nested-configuration/index.md b/blog-website/blog/2018-07-28-azure-app-service-web-app-containers-asp-net-nested-configuration/index.md index e6d86a5ffd8..9b20138b8ff 100644 --- a/blog-website/blog/2018-07-28-azure-app-service-web-app-containers-asp-net-nested-configuration/index.md +++ b/blog-website/blog/2018-07-28-azure-app-service-web-app-containers-asp-net-nested-configuration/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [] image: ./appservice_classic.webp hide_table_of_contents: false +description: 'Learn how to configure an ASP.NET application in Azure App Service Web App for Containers without colons. Use a double underscore instead.' --- How can we configure an ASP.NET application with nested properties [Azure App Service Web App for Containers](https://azure.microsoft.com/en-gb/services/app-service/containers/) using Application Settings in Azure? Colons don't work. diff --git a/blog-website/blog/2018-08-21-typescript-webpack-alias-goodbye-relative-paths/index.md b/blog-website/blog/2018-08-21-typescript-webpack-alias-goodbye-relative-paths/index.md index 0692d6a2842..6afc9eaa4d0 100644 --- a/blog-website/blog/2018-08-21-typescript-webpack-alias-goodbye-relative-paths/index.md +++ b/blog-website/blog/2018-08-21-typescript-webpack-alias-goodbye-relative-paths/index.md @@ -4,6 +4,7 @@ title: 'Using TypeScript and webpack alias: goodbye relative paths' authors: johnnyreilly tags: [typescript, webpack] hide_table_of_contents: false +description: 'Use TypeScript with webpack alias to avoid long relative paths in imports. Try `path mapping` or `resolve.alias`. Use `tsconfig-paths-webpack-plugin`.' --- This post shows how you can use TypeScript with webpack `alias` to move away from using relative paths in your `import` statements. diff --git a/blog-website/blog/2018-09-15-semantic-versioning-and-definitely-typed/index.md b/blog-website/blog/2018-09-15-semantic-versioning-and-definitely-typed/index.md index 8b5a0301fbd..95f488969b3 100644 --- a/blog-website/blog/2018-09-15-semantic-versioning-and-definitely-typed/index.md +++ b/blog-website/blog/2018-09-15-semantic-versioning-and-definitely-typed/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Definitely Typed, typescript] image: ./i-must-break-you.webp hide_table_of_contents: false +description: 'Definitely Typed lacks semantic versioning, causing build failures. Use specific package versions, and breaking changes can be positive.' --- This a tale of things that are and things that aren't. It's a tale of semantic versioning, the lack thereof and heartbreak. It's a story of terror and failing builds. But it has a bittersweet ending wherein our heroes learn a lesson and understand the need for compromise. We all come out better and wiser people. Hopefully there's something for everybody; let's start with an exciting opener and see where it goes... diff --git a/blog-website/blog/2018-09-23-ts-loader-project-references-first-blood/index.md b/blog-website/blog/2018-09-23-ts-loader-project-references-first-blood/index.md index a66498521c1..c9b710364c5 100644 --- a/blog-website/blog/2018-09-23-ts-loader-project-references-first-blood/index.md +++ b/blog-website/blog/2018-09-23-ts-loader-project-references-first-blood/index.md @@ -2,8 +2,9 @@ slug: ts-loader-project-references-first-blood title: 'ts-loader Project References: First Blood' authors: johnnyreilly -tags: [typescript, project references, ts-loader, Webpack] +tags: [typescript, project references, ts-loader, webpack] hide_table_of_contents: false +description: 'ts-loader now supports TypeScripts project references. However, composite projects built with `outDir` on Windows cannot be consumed by ts-loader... yet' --- So [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) eh? They shipped with [TypeScript 3](https://blogs.msdn.microsoft.com/typescript/2018/07/30/announcing-typescript-3-0/#project-references). We've just shipped initial support for project references in [`ts-loader v5.2.0`](https://github.com/TypeStrong/ts-loader/releases/tag/v5.2.0). All the hard work was done by the amazing [Andrew Branch](https://twitter.com/atcb). In fact I'd recommend taking a gander at [the PR](https://github.com/TypeStrong/ts-loader/pull/817). Yay Andrew! diff --git a/blog-website/blog/2018-10-07-font-awesome-brand-icons-react/index.md b/blog-website/blog/2018-10-07-font-awesome-brand-icons-react/index.md index 75545aa1048..20572367c38 100644 --- a/blog-website/blog/2018-10-07-font-awesome-brand-icons-react/index.md +++ b/blog-website/blog/2018-10-07-font-awesome-brand-icons-react/index.md @@ -4,6 +4,7 @@ title: 'Brand New Fonting Awesomeness' authors: johnnyreilly tags: [React] hide_table_of_contents: false +description: 'Learn how to use brand icons with Font Awesome 5 in React with these helpful instructions on @fortawesome/free-brands-svg-icons.' --- Love me some [Font Awesome](https://fontawesome.com). Absolutely wonderful. However, I came a cropper when following the instructions [on using the all new Font Awesome 5 with React](https://fontawesome.com/how-to-use/on-the-web/using-with/react). The instructions for standard icons work _fine_. But if you want to use brand icons then this does not help you out much. There's 2 problems: diff --git a/blog-website/blog/2018-10-27-making-a-programmer/index.md b/blog-website/blog/2018-10-27-making-a-programmer/index.md index 4f99b6b4abe..87e5689bd7f 100644 --- a/blog-website/blog/2018-10-27-making-a-programmer/index.md +++ b/blog-website/blog/2018-10-27-making-a-programmer/index.md @@ -3,6 +3,7 @@ slug: making-a-programmer title: 'Making a Programmer' authors: johnnyreilly hide_table_of_contents: false +description: 'Learn programming in a relaxed atmosphere with a coding bootcamp that values repetition, feedback and team facilitation.' --- I recently had the good fortune to help run a coding bootcamp. The idea was simple: there are many people around us who are interested in programming but don't know where to start. Let's take some folk who do and share the knowledge. diff --git a/blog-website/blog/2018-11-17-snapshot-testing-for-c/index.md b/blog-website/blog/2018-11-17-snapshot-testing-for-c/index.md index 0b69b07187f..ee6cad29633 100644 --- a/blog-website/blog/2018-11-17-snapshot-testing-for-c/index.md +++ b/blog-website/blog/2018-11-17-snapshot-testing-for-c/index.md @@ -4,6 +4,7 @@ title: 'Snapshot Testing for C#' authors: johnnyreilly tags: [snapshot testing, c#, jest] hide_table_of_contents: false +description: 'Snapshot testing is an efficient test technique for comparing outputs with JSON. Its applicable to C# too, using Fluent Assertions and a helper tool.' --- If you're a user of Jest, you've no doubt heard of and perhaps made use of [snapshot testing](https://jestjs.io/docs/en/snapshot-testing). diff --git a/blog-website/blog/2018-12-22-you-might-not-need-thread-loader/index.md b/blog-website/blog/2018-12-22-you-might-not-need-thread-loader/index.md index 5c092aeda7d..122ccec79fc 100644 --- a/blog-website/blog/2018-12-22-you-might-not-need-thread-loader/index.md +++ b/blog-website/blog/2018-12-22-you-might-not-need-thread-loader/index.md @@ -4,6 +4,7 @@ title: 'You Might Not Need thread-loader' authors: johnnyreilly tags: [fork-ts-checker-webpack-plugin, ts-loader, webpack] hide_table_of_contents: false +description: 'Jan Nicklas, the creator of webpack-config-plugins, suggests limiting the use of thread-loader for costly operations via `poolTimeout: Infinity`.' --- It all started with a GitHub issue. [Ernst Ammann reported](https://github.com/namics/webpack-config-plugins/issues/24): diff --git a/blog-website/blog/2019-01-05-github-actions-and-yarn/index.md b/blog-website/blog/2019-01-05-github-actions-and-yarn/index.md index 2a9c219d47d..ad0bec8d344 100644 --- a/blog-website/blog/2019-01-05-github-actions-and-yarn/index.md +++ b/blog-website/blog/2019-01-05-github-actions-and-yarn/index.md @@ -4,6 +4,7 @@ title: 'GitHub Actions and Yarn' authors: johnnyreilly tags: [docker, yarn, GitHub Actions] hide_table_of_contents: false +description: 'Automate npm publishing using GitHub Actions; use `npm` GitHub Action with yarn or any Docker container with Node/npm installed.' --- I'd been meaning to automate the npm publishing of [`ts-loader`](https://github.com/TypeStrong/ts-loader) for the longest time. I had attempted to use Travis to do this in the same way as [`fork-ts-checker-webpack-plugin`](https://github.com/Realytics/fork-ts-checker-webpack-plugin). Alas using secure environment variables in Travis has unfortunate implications for ts-loader's test pack. diff --git a/blog-website/blog/2019-01-13-typescript-and-webpack-watch-it/index.md b/blog-website/blog/2019-01-13-typescript-and-webpack-watch-it/index.md index 68291057f33..daec41dc0fb 100644 --- a/blog-website/blog/2019-01-13-typescript-and-webpack-watch-it/index.md +++ b/blog-website/blog/2019-01-13-typescript-and-webpack-watch-it/index.md @@ -4,6 +4,7 @@ title: 'TypeScript and webpack: Watch It' authors: johnnyreilly tags: [typescript, webpack] hide_table_of_contents: false +description: 'TypeScripts "watch" API shortens time between incremental builds for quicker development; updates are available for fork-ts-checker-webpack-plugin.' --- All I ask for is a compiler and a tight feedback loop. Narrowing the gap between making a change to a program and seeing the effect of that is a productivity boon. The TypeScript team are wise cats and dig this. They've taken strides to improve the developer experience of TypeScript users by [introducing a "watch" API which can be leveraged by other tools](https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#writing-an-incremental-program-watcher). To quote the docs: diff --git a/blog-website/blog/2019-02-22-aspnet-core-allowlist-proxying-http-requests/index.md b/blog-website/blog/2019-02-22-aspnet-core-allowlist-proxying-http-requests/index.md index 5cc161bf660..c54c7cde47d 100644 --- a/blog-website/blog/2019-02-22-aspnet-core-allowlist-proxying-http-requests/index.md +++ b/blog-website/blog/2019-02-22-aspnet-core-allowlist-proxying-http-requests/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [.NET] image: ./hang-on-lads-ive-got-a-great-idea.webp hide_table_of_contents: false +description: 'ASP.NET Core can proxy HTTP requests selectively, allowing only acceptable traffic via a middleware for specified paths.' --- This post demonstrates a mechanism for proxying HTTP requests in ASP.NET Core. It doesn't proxy all requests; it only proxies requests that match entries on an "allowlist" - so we only proxy the traffic that we've actively decided is acceptable as determined by taking the form of an expected URL and HTTP verb (GET / POST etc). diff --git a/blog-website/blog/2019-03-06-fork-ts-checker-webpack-plugin-v1/index.md b/blog-website/blog/2019-03-06-fork-ts-checker-webpack-plugin-v1/index.md index 7b6fef36126..19e7442e040 100644 --- a/blog-website/blog/2019-03-06-fork-ts-checker-webpack-plugin-v1/index.md +++ b/blog-website/blog/2019-03-06-fork-ts-checker-webpack-plugin-v1/index.md @@ -4,6 +4,7 @@ title: 'fork-ts-checker-webpack-plugin v1.0' authors: johnnyreilly tags: [typescript, fork-ts-checker-webpack-plugin, ts-loader, tslint, webpack] hide_table_of_contents: false +description: '`fork-ts-checker-webpack-plugin` released v1.0.0 with TypeScript 3+ support, incremental watch API by default, and compatibility with webpack and TSLint.' --- [It's time for the first major version of `fork-ts-checker-webpack-plugin`](https://github.com/Realytics/fork-ts-checker-webpack-plugin/releases/tag/v1.0.0). It's been a long time coming :-) diff --git a/blog-website/blog/2019-03-22-google-analytics-api-and-aspnet-core/index.md b/blog-website/blog/2019-03-22-google-analytics-api-and-aspnet-core/index.md index c7ce935d48a..73e18e7b37d 100644 --- a/blog-website/blog/2019-03-22-google-analytics-api-and-aspnet-core/index.md +++ b/blog-website/blog/2019-03-22-google-analytics-api-and-aspnet-core/index.md @@ -4,6 +4,7 @@ title: 'Google Analytics API and ASP.Net Core' authors: johnnyreilly tags: [asp net core, google analytics] hide_table_of_contents: false +description: 'Accessing Google Analytics API from ASP.Net Core can be tough due to lack of examples. This article provides an example code to get page access stats.' --- I recently had need to be able to access the API for Google Analytics from ASP.Net Core. Getting this up and running turned out to be surprisingly tough because of an absence of good examples. So here it is; an example of how you can access a simple page access stat using [the API](https://www.nuget.org/packages/Google.Apis.AnalyticsReporting.v4/): diff --git a/blog-website/blog/2019-03-24-template-tricks-for-dainty-dom/index.md b/blog-website/blog/2019-03-24-template-tricks-for-dainty-dom/index.md index d3333990fb6..00a4219223a 100644 --- a/blog-website/blog/2019-03-24-template-tricks-for-dainty-dom/index.md +++ b/blog-website/blog/2019-03-24-template-tricks-for-dainty-dom/index.md @@ -4,6 +4,7 @@ title: 'Template Tricks for a Dainty DOM' authors: johnnyreilly tags: [Materialized] hide_table_of_contents: false +description: 'Wrapping data in HTML templates can help with performance. This trick kept rendering server-side but only rendered content when necessary.' --- I'm somewhat into code golf. Placing restrictions on what you're "allowed" to do in code and seeing what the happens as a result. I'd like to share with you something that came out of some recent dabblings. diff --git a/blog-website/blog/2019-04-27-react-select-with-less-typing-lag/index.md b/blog-website/blog/2019-04-27-react-select-with-less-typing-lag/index.md index 95ad7c0cb78..7765ae66995 100644 --- a/blog-website/blog/2019-04-27-react-select-with-less-typing-lag/index.md +++ b/blog-website/blog/2019-04-27-react-select-with-less-typing-lag/index.md @@ -4,6 +4,7 @@ title: 'react-select with less typing lag' authors: johnnyreilly tags: [react-select] hide_table_of_contents: false +description: 'Fix lagging in `react-select`. Change `filterOption` to `ignoreAccents: false` for faster typing experience with 1000+ items.' --- This is going out to all those people using [`react-select`](https://react-select.com) with 1000+ items to render. To those people typing into the select and saying out loud "it's _so_ laggy.... This can't be... It's 2019... I mean, right?" To the people who read this [GitHub issue](https://github.com/JedWatson/react-select/issues/3128) top to bottom 30 times and still came back unsure of what to do. This is for you. diff --git a/blog-website/blog/2019-05-23-typescript-and-high-cpu-usage-watch/index.md b/blog-website/blog/2019-05-23-typescript-and-high-cpu-usage-watch/index.md index 2f907c77452..b26e08cf163 100644 --- a/blog-website/blog/2019-05-23-typescript-and-high-cpu-usage-watch/index.md +++ b/blog-website/blog/2019-05-23-typescript-and-high-cpu-usage-watch/index.md @@ -4,6 +4,7 @@ title: "TypeScript and high CPU usage - watch don't stare!" authors: johnnyreilly tags: [typescript, fork-ts-checker-webpack-plugin, webpack] hide_table_of_contents: false +description: 'High CPU usage in watch mode on idle due to TypeScripts fs.watchFile. fs.watch recommended instead. Env variable controls file watching.' --- I'm one of the maintainers of the [fork-ts-checker-webpack-plugin](https://github.com/Realytics/fork-ts-checker-webpack-plugin). Hi there! @@ -33,6 +34,7 @@ John also found that there are other file watching behaviours offered by TypeScr John did some rough benchmarking of the performance of the different options that be set on his PC running linux 64 bit. Here's how it came out: +``` | Value | CPU usage on idle | | ------------------------------------- | ----------------- | | TS default _(TSC_WATCHFILE not set)_ | **7\.4%** | @@ -41,6 +43,7 @@ John did some rough benchmarking of the performance of the different options tha | PriorityPollingInterval | **6\.2%** | | DynamicPriorityPolling | 0\.5% | | UseFsEvents | 0\.2% | +``` As you can see, the default performs poorly. On the other hand, an option like `UseFsEventsWithFallbackDynamicPolling` is comparative greasy lightning. diff --git a/blog-website/blog/2019-06-07-typescript-webpack-you-down-with-pnp/index.md b/blog-website/blog/2019-06-07-typescript-webpack-you-down-with-pnp/index.md index b80bbfaa313..f650f2d2bd2 100644 --- a/blog-website/blog/2019-06-07-typescript-webpack-you-down-with-pnp/index.md +++ b/blog-website/blog/2019-06-07-typescript-webpack-you-down-with-pnp/index.md @@ -4,6 +4,7 @@ title: 'TypeScript / webpack - you down with PnP? Yarn, you know me!' authors: johnnyreilly tags: [typescript, yarn, webpack, PnP] hide_table_of_contents: false +description: 'Yarn PnP speeds up module installation and eliminates node_modules. Converting to it is easy but some rough edges exist.' --- Yarn PnP is an innovation by the Yarn team designed to speed up module resolution by node. To quote the [(excellent) docs](https://yarnpkg.com/en/docs/pnp): diff --git a/blog-website/blog/2019-07-13-typescript-and-eslint-meet-fork-ts-checker-webpack-plugin/index.md b/blog-website/blog/2019-07-13-typescript-and-eslint-meet-fork-ts-checker-webpack-plugin/index.md index cb4e66d80b7..baf3720813a 100644 --- a/blog-website/blog/2019-07-13-typescript-and-eslint-meet-fork-ts-checker-webpack-plugin/index.md +++ b/blog-website/blog/2019-07-13-typescript-and-eslint-meet-fork-ts-checker-webpack-plugin/index.md @@ -4,6 +4,7 @@ title: 'Using TypeScript and ESLint with webpack (fork-ts-checker-webpack-plugin authors: johnnyreilly tags: [eslint, typescript, fork-ts-checker-webpack-plugin, webpack] hide_table_of_contents: false +description: 'The `fork-ts-checker-webpack-plugin` adds support for ESLint. Replace TSLint with related packages in `package.json` and configure with `.eslintrc.js`.' --- The `fork-ts-checker-webpack-plugin` has, since its inception, performed two classes of checking: diff --git a/blog-website/blog/2019-08-02-asp-net-authentication-hard-coding-claims/index.md b/blog-website/blog/2019-08-02-asp-net-authentication-hard-coding-claims/index.md index 3173819d2fb..a0f2f60fbf8 100644 --- a/blog-website/blog/2019-08-02-asp-net-authentication-hard-coding-claims/index.md +++ b/blog-website/blog/2019-08-02-asp-net-authentication-hard-coding-claims/index.md @@ -4,6 +4,7 @@ title: 'ASP.NET Core authentication: hard-coding a claim in development' authors: johnnyreilly tags: [ASP.Net Core, Authentication] hide_table_of_contents: false +description: 'The DevelopmentModeAuthenticationHandler allows ASP.NET Core developers to hard code user authentication claims during development, easing testing.' --- This post demonstrates how you can hard code user authentication claims in ASP.NET Core; a useful technique to facilate testing during development. diff --git a/blog-website/blog/2019-08-17-symbiotic-definitely-typed/index.md b/blog-website/blog/2019-08-17-symbiotic-definitely-typed/index.md index 187c6b97cd3..a8540876811 100644 --- a/blog-website/blog/2019-08-17-symbiotic-definitely-typed/index.md +++ b/blog-website/blog/2019-08-17-symbiotic-definitely-typed/index.md @@ -4,6 +4,7 @@ title: 'Symbiotic Definitely Typed' authors: johnnyreilly tags: [typescript, react-testing-library, Definitely Typed] hide_table_of_contents: false +description: 'New approach by `react-testing-library` improves TypeScript experience. Type definitions are maintained separately for `@testing-library/react`.' --- I did ponder calling this post "how to enable a good TypeScript developer experience for npm modules that aren't written in TypeScript"... Not exactly pithy though. diff --git a/blog-website/blog/2019-09-14-coming-soon-definitely-typed/index.md b/blog-website/blog/2019-09-14-coming-soon-definitely-typed/index.md index 2e21ded47b0..e03088a6c90 100644 --- a/blog-website/blog/2019-09-14-coming-soon-definitely-typed/index.md +++ b/blog-website/blog/2019-09-14-coming-soon-definitely-typed/index.md @@ -4,6 +4,7 @@ title: 'Coming Soon: Definitely Typed' authors: johnnyreilly tags: [typescript, Definitely Typed] hide_table_of_contents: false +description: 'The story of Definitely Typed, a project aiming to provide type definitions for JavaScript libraries, from creation to top 10 in GitHub in 2018.' --- A long time ago (well, 2012) in a galaxy far, far away (okay; Plovdiv, Bulgaria).... diff --git a/blog-website/blog/2019-09-30-start-me-up-ts-loader-meet-tsbuildinfo/index.md b/blog-website/blog/2019-09-30-start-me-up-ts-loader-meet-tsbuildinfo/index.md index aa0f2e75a24..4308f49caa0 100644 --- a/blog-website/blog/2019-09-30-start-me-up-ts-loader-meet-tsbuildinfo/index.md +++ b/blog-website/blog/2019-09-30-start-me-up-ts-loader-meet-tsbuildinfo/index.md @@ -4,6 +4,7 @@ title: 'Start Me Up: ts-loader meet .tsbuildinfo' authors: johnnyreilly tags: [ts-loader, typescript] hide_table_of_contents: false +description: 'TypeScript 3.4 introduced `.tsbuildinfo` files for faster compilations. With TypeScript 3.6, APIs landed to enable third party tool integration.' --- With TypeScript 3.4, [a new behaviour landed and a magical new file type appeared; `.tsbuildinfo`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html) diff --git a/blog-website/blog/2019-10-08-definitely-typed-the-movie/index.md b/blog-website/blog/2019-10-08-definitely-typed-the-movie/index.md index f030fd235d1..725704a4d06 100644 --- a/blog-website/blog/2019-10-08-definitely-typed-the-movie/index.md +++ b/blog-website/blog/2019-10-08-definitely-typed-the-movie/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [typescript, Definitely Typed] image: ./title-image.png hide_table_of_contents: false +description: 'The history of the TypeScript GitHub project Definitely Typed. And some TypeScript history as well' --- I'd like to tell you a story. It's the tale of the ecosystem that grew up around a language: TypeScript. TypeScript is, for want of a better description, JavaScript after a trip to Saville Row. Essentially the same language, but a little more together, a little less wild west. JS with a decent haircut and a new suit. These days, the world seems to be written in TypeScript. And when you pause to consider just how young the language is, well, that's kind of amazing. @@ -103,7 +104,7 @@ So, imagine your definition looked like this: ```ts declare function turnANumberIntoAString( - numberToMakeStringOutOf: number + numberToMakeStringOutOf: number, ): string; ``` @@ -165,7 +166,7 @@ On December 28th 2013 Basarat decided that a regular contributor to Definitely T ![A photograph of John Reilly](johnny_reilly.webp) -That's me. Or [johnny_reilly on Twitter](https://twitter.com/johnny_reilly), [johnny_reilly on Fosstodon](https://fosstodon.org/@johnny_reilly) and [johnnyreilly on GitHub](https://github.com/johnnyreilly). Relatively few people call me Johnny. I'm named that online because back when I applied for an email address, someone had already bagsied `johnreilly@hotmail.com`. (Hotmail was what everyone used back when I came online - I am *that* old.) So rather than sully my handle with a number or a middle name I settled for `johnny_reilly` and went with the underscore as someone already had the email address without one. I haven't looked back and have generally tried to keep that nom de plume wherever I lay my hat online. I have learned to my chagrin that GitHub doesn't support the `_` character in usernames. This bothers me more than is reasonable. +That's me. Or [johnny_reilly on Twitter](https://twitter.com/johnny_reilly), [johnny_reilly on Fosstodon](https://fosstodon.org/@johnny_reilly) and [johnnyreilly on GitHub](https://github.com/johnnyreilly). Relatively few people call me Johnny. I'm named that online because back when I applied for an email address, someone had already bagsied `johnreilly@hotmail.com`. (Hotmail was what everyone used back when I came online - I am _that_ old.) So rather than sully my handle with a number or a middle name I settled for `johnny_reilly` and went with the underscore as someone already had the email address without one. I haven't looked back and have generally tried to keep that nom de plume wherever I lay my hat online. I have learned to my chagrin that GitHub doesn't support the `_` character in usernames. This bothers me more than is reasonable. In contrast to others I was a relatively late starter to TypeScript. I was intrigued right from the initial announcement, but held off from properly getting my hands dirty until generics was added to the language in 0.9. (This predisposition towards generics in a language perhaps explains why I didn't get too far with Golang.) diff --git a/blog-website/blog/2019-12-18-teams-notification-webhooks/index.md b/blog-website/blog/2019-12-18-teams-notification-webhooks/index.md index 424c08f4b13..5c1dafe7337 100644 --- a/blog-website/blog/2019-12-18-teams-notification-webhooks/index.md +++ b/blog-website/blog/2019-12-18-teams-notification-webhooks/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Microsoft Teams, webhook] image: ./teams-notification.gif hide_table_of_contents: false +description: 'Learn how to automate notifications using Microsoft Teams and Markdown webhooks, and discover how to use ASP.Net Core to send notifications.' --- Teams notifications are mighty useful. You can send them using Markdown via a webhook. diff --git a/blog-website/blog/2020-01-02-ef-core-31-breaks-left-join-with-no-navigation-property/index.md b/blog-website/blog/2020-01-02-ef-core-31-breaks-left-join-with-no-navigation-property/index.md index 66f1011f3bd..13ce1c5a535 100644 --- a/blog-website/blog/2020-01-02-ef-core-31-breaks-left-join-with-no-navigation-property/index.md +++ b/blog-website/blog/2020-01-02-ef-core-31-breaks-left-join-with-no-navigation-property/index.md @@ -4,6 +4,7 @@ title: 'EF Core 3.1 breaks left join with no navigation property' authors: johnnyreilly tags: [Entity Framework] hide_table_of_contents: false +description: 'When upgrading from .NET Core 2.2 to 3.1, an invalid LEFT JOIN error was encountered. The issue was resolved by adding Navigation property.' --- Just recently my team took on the challenge of upgrading our codebase from .NET Core 2.2 to .NET Core 3.1. Along the way we encountered a quirky issue which caused us much befuddlement. Should you be befuddled too, then maybe this can help you. diff --git a/blog-website/blog/2020-01-21-license-to-kill-your-pwa/index.md b/blog-website/blog/2020-01-21-license-to-kill-your-pwa/index.md index ad572e89eb9..726dcde0a93 100644 --- a/blog-website/blog/2020-01-21-license-to-kill-your-pwa/index.md +++ b/blog-website/blog/2020-01-21-license-to-kill-your-pwa/index.md @@ -4,6 +4,7 @@ title: 'LICENSE to kill your PWA' authors: johnnyreilly tags: [] hide_table_of_contents: false +description: 'Creating `.LICENSE` files caused issues for a PWA. The `terser-webpack-plugin` was changed to make `.LICENSE.txt` files instead.' --- ## Update: 26/01/2020 - LICENSE to kill revoked! diff --git a/blog-website/blog/2020-01-31-from-create-react-app-to-pwa/index.md b/blog-website/blog/2020-01-31-from-create-react-app-to-pwa/index.md index 68ffe8041af..49cbb90d53a 100644 --- a/blog-website/blog/2020-01-31-from-create-react-app-to-pwa/index.md +++ b/blog-website/blog/2020-01-31-from-create-react-app-to-pwa/index.md @@ -4,6 +4,7 @@ title: 'From create-react-app to PWA' authors: johnnyreilly tags: [create-react-app, PWA] hide_table_of_contents: false +description: 'Learn how to build a basic Progressive Web App with React and TypeScript, as well as how to add features like code splitting and deployment.' --- Progressive Web Apps are a (terribly named) wonderful idea. You can build an app _once_ using web technologies which serves all devices and form factors. It can be accessible over the web, but also surface on the home screen of your Android / iOS device. That app can work offline, have a splash screen when it launches and have notifications too. diff --git a/blog-website/blog/2020-02-21-web-workers-comlink-typescript-and-react/index.md b/blog-website/blog/2020-02-21-web-workers-comlink-typescript-and-react/index.md index 9859dbf2b13..3b617bbfd42 100644 --- a/blog-website/blog/2020-02-21-web-workers-comlink-typescript-and-react/index.md +++ b/blog-website/blog/2020-02-21-web-workers-comlink-typescript-and-react/index.md @@ -4,6 +4,7 @@ title: 'Web Workers, comlink, TypeScript and React' authors: johnnyreilly tags: [typescript, React] hide_table_of_contents: false +description: 'Learn how to use Web Workers in a React app using Googles comlink library. Offload long-running calculations to a separate thread.' --- JavaScript is famously single threaded. However, if you're developing for the web, you may well know that this is not quite accurate. There are [`Web Workers`](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers): @@ -343,7 +344,7 @@ import { useEffect, useState, useMemo } from 'react'; */ export function useTakeALongTimeToAddTwoNumbers( number1: number, - number2: number + number2: number, ) { // We'll want to expose a wrapping object so we know when a calculation is in progress const [data, setData] = useState({ diff --git a/blog-website/blog/2020-03-22-dual-boot-authentication-with-aspnetcore/index.md b/blog-website/blog/2020-03-22-dual-boot-authentication-with-aspnetcore/index.md index 6dd733e8140..f06e0dc2626 100644 --- a/blog-website/blog/2020-03-22-dual-boot-authentication-with-aspnetcore/index.md +++ b/blog-website/blog/2020-03-22-dual-boot-authentication-with-aspnetcore/index.md @@ -4,6 +4,7 @@ title: 'Dual boot authentication with ASP.NET' authors: johnnyreilly tags: [Authentication, Azure AD, ASP.NET] hide_table_of_contents: false +description: 'The article explains how to have different authentication methods for two classes of users accessing an app. Code snippets are provided.' --- This is a post about having two kinds of authentication working at the same time in ASP.Net Core. But choosing which authentication method to use dynamically at runtime; based upon the criteria of your choice. diff --git a/blog-website/blog/2020-03-29-offline-storage-in-pwa/index.md b/blog-website/blog/2020-03-29-offline-storage-in-pwa/index.md index 9b716cd4f6b..a77b0cd50b4 100644 --- a/blog-website/blog/2020-03-29-offline-storage-in-pwa/index.md +++ b/blog-website/blog/2020-03-29-offline-storage-in-pwa/index.md @@ -4,6 +4,7 @@ title: 'Offline storage in a PWA' authors: johnnyreilly tags: [PWA] hide_table_of_contents: false +description: 'Learn how to use IndexedDB for offline storage in your web app or PWA with the IDB-Keyval library and a React custom hook.' --- When you are building any kind of application it's typical to want to store information which persists beyond a single user session. Sometimes that will be information that you'll want to live in some kind of centralised database, but not always. @@ -82,7 +83,7 @@ async function testIDBKeyval() { await set('hello', 'world'); const whatDoWeHave = await get('hello'); console.log( - `When we queried idb-keyval for 'hello', we found: ${whatDoWeHave}` + `When we queried idb-keyval for 'hello', we found: ${whatDoWeHave}`, ); } @@ -179,7 +180,7 @@ function App() { useEffect(() => { get('darkModeOn').then((value) => // If a value is retrieved then use it; otherwise default to true - setDarkModeOn(value ?? true) + setDarkModeOn(value ?? true), ); }, [setDarkModeOn]); @@ -249,14 +250,14 @@ import { set, get } from 'idb-keyval'; export function usePersistedState( keyToPersistWith: string, - defaultState: TState + defaultState: TState, ) { const [state, setState] = useState(undefined); useEffect(() => { get(keyToPersistWith).then((retrievedState) => // If a value is retrieved then use it; otherwise default to defaultValue - setState(retrievedState ?? defaultState) + setState(retrievedState ?? defaultState), ); }, [keyToPersistWith, setState, defaultState]); @@ -265,7 +266,7 @@ export function usePersistedState( setState(newValue); set(keyToPersistWith, newValue); }, - [keyToPersistWith, setState] + [keyToPersistWith, setState], ); return [state, setPersistedValue] as const; @@ -290,7 +291,7 @@ const sharedStyles = { function App() { const [darkModeOn, setDarkModeOn] = usePersistedState( 'darkModeOn', - true + true, ); const handleOnChange = ({ target }: React.ChangeEvent) => diff --git a/blog-website/blog/2020-04-04-up-to-clouds/index.md b/blog-website/blog/2020-04-04-up-to-clouds/index.md index 1199444b45a..00bcd33921d 100644 --- a/blog-website/blog/2020-04-04-up-to-clouds/index.md +++ b/blog-website/blog/2020-04-04-up-to-clouds/index.md @@ -4,6 +4,7 @@ title: 'Up to the clouds!' authors: johnnyreilly tags: [docker, kubernetes, asp net core] hide_table_of_contents: false +description: 'Migrating ASP.NET Core app from on-prem to cloud with Kubernetes, Docker, Jenkins, Vault & Azure AD Single Sign-On for greater efficiency.' --- This last four months has been quite the departure for me. Most typically I find myself building applications; for this last period of time I've been taking the platform that I work on, and been migrating it from running on our on premise servers to running in the cloud. diff --git a/blog-website/blog/2020-05-10-from-react-window-to-react-virtual/index.md b/blog-website/blog/2020-05-10-from-react-window-to-react-virtual/index.md index cb7b337c35e..e41381c9763 100644 --- a/blog-website/blog/2020-05-10-from-react-window-to-react-virtual/index.md +++ b/blog-website/blog/2020-05-10-from-react-window-to-react-virtual/index.md @@ -4,6 +4,7 @@ title: 'From react-window to react-virtual' authors: johnnyreilly tags: [react-virtual, react-window, React] hide_table_of_contents: false +description: 'Switch from `react-window` to `react-virtual` for simpler code, TypeScript support and improved perceived performance.' --- The tremendous [Tanner Linsley](https://twitter.com/tannerlinsley) recently released [`react-virtual`](https://github.com/tannerlinsley/react-virtual). `react-virtual` provides "hooks for virtualizing scrollable elements in React". @@ -73,7 +74,7 @@ const ImportantDataList: React.FC = React.memo( > {RenderRow} - ) + ), ); type ListItemProps = { @@ -149,7 +150,7 @@ const ImportantDataList: React.FC = React.memo( ); - } + }, ); ``` diff --git a/blog-website/blog/2020-05-21-autofac-webapplicationfactory-integration-tests/index.md b/blog-website/blog/2020-05-21-autofac-webapplicationfactory-integration-tests/index.md index c02fc8d6093..47ac110822b 100644 --- a/blog-website/blog/2020-05-21-autofac-webapplicationfactory-integration-tests/index.md +++ b/blog-website/blog/2020-05-21-autofac-webapplicationfactory-integration-tests/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [autofac, ASP.Net Core, Integration Testing] image: ./autofac-webapplicationfactory-tests.webp hide_table_of_contents: false +description: 'A bug in ASP.NET Core v3.0 thwarts swapping in Autofac as an IOC container in WebApplicationFactory tests. A workaround exists.' --- **Updated 2nd Oct 2020:** _for an approach that works with Autofac 6 and `ConfigureTestContainer` see [this post](../2020-10-02-autofac-6-integration-tests-and-generic-hosting/index.md)._ diff --git a/blog-website/blog/2020-06-21-taskwhenall-select-is-footgun/index.md b/blog-website/blog/2020-06-21-taskwhenall-select-is-footgun/index.md index 1992d23f69c..d5550fe6902 100644 --- a/blog-website/blog/2020-06-21-taskwhenall-select-is-footgun/index.md +++ b/blog-website/blog/2020-06-21-taskwhenall-select-is-footgun/index.md @@ -4,6 +4,7 @@ title: 'Task.WhenAll / Select is a footgun 👟🔫' authors: johnnyreilly tags: [C#, LINQ] hide_table_of_contents: false +description: 'The writer warns against LINQ code that causes concurrent API requests and shares plans for better metrics and a development container.' --- This post differs from my typical fayre. Most often I write "here's how to do a thing". This is not that. It's more "don't do this thing I did". And maybe also, "how can we avoid a situation like this happening again in future?". On this topic I very much don't have all the answers - but by putting my thoughts down maybe I'll learn and maybe others will educate me. I would love that! diff --git a/blog-website/blog/2020-07-11-devcontainers-and-ssl-interception/index.md b/blog-website/blog/2020-07-11-devcontainers-and-ssl-interception/index.md index 0f0dc689892..861b31e7982 100644 --- a/blog-website/blog/2020-07-11-devcontainers-and-ssl-interception/index.md +++ b/blog-website/blog/2020-07-11-devcontainers-and-ssl-interception/index.md @@ -4,6 +4,7 @@ title: 'Devcontainers and SSL interception' authors: johnnyreilly tags: [devcontainer, ssl interception] hide_table_of_contents: false +description: 'Developers may need to overcome MITM certificate issues to use devcontainers, which can optimize productivity for new starters when developing software.' --- [Devcontainers](https://code.visualstudio.com/docs/remote/containers) are cool. They are the infrastructure as code equivalent for developing software. diff --git a/blog-website/blog/2020-08-09-devcontainers-aka-performance-in-secure/index.md b/blog-website/blog/2020-08-09-devcontainers-aka-performance-in-secure/index.md index 15ebb680070..32e31a85b13 100644 --- a/blog-website/blog/2020-08-09-devcontainers-aka-performance-in-secure/index.md +++ b/blog-website/blog/2020-08-09-devcontainers-aka-performance-in-secure/index.md @@ -4,6 +4,7 @@ title: 'Devcontainers AKA performance in a secure sandbox' authors: johnnyreilly tags: [devcontainer] hide_table_of_contents: false +description: 'Speedy ASP.NET Core and JavaScript development is made possible by devcontainers, which isolate tools and code to improve productivity.' --- Many corporate machines arrive in engineers hands with a preponderance of pre-installed background tools; from virus checkers to backup utilities to port blockers; the list is long. @@ -70,8 +71,8 @@ Enough talk... We're going to need a `.devcontainer/devcontainer.json`: Now the `docker-compose.devcontainer.yml` which lives in the root of the project. It provisions a SQL Server container (using the official image) and our devcontainer: -``` -version: "3.7" +```yml +version: '3.7' services: my-devcontainer: image: my-devcontainer @@ -85,8 +86,8 @@ services: # user: vscode ports: - - "5000:5000" - - "8080:8080" + - '5000:5000' + - '8080:8080' environment: - CONNECTIONSTRINGS__MYDATABASECONNECTION depends_on: @@ -97,13 +98,13 @@ services: ports: - 1433:1433 environment: - SA_PASSWORD: "Your_password123" - ACCEPT_EULA: "Y" + SA_PASSWORD: 'Your_password123' + ACCEPT_EULA: 'Y' ``` The devcontainer will be built with the `Dockerfile.devcontainer` in the root of our repo. It relies upon your SSH keys and a `.env` file being available to be copied in: -``` +```Dockerfile #----------------------------------------------------------------------------------------------------------- # Based upon: https://github.com/microsoft/vscode-dev-containers/tree/master/containers/dotnetcore #----------------------------------------------------------------------------------------------------------- diff --git a/blog-website/blog/2020-09-04-why-your-team-needs-newsfeed/index.md b/blog-website/blog/2020-09-04-why-your-team-needs-newsfeed/index.md index b6ad2e45c69..a11c4ae8db8 100644 --- a/blog-website/blog/2020-09-04-why-your-team-needs-newsfeed/index.md +++ b/blog-website/blog/2020-09-04-why-your-team-needs-newsfeed/index.md @@ -3,6 +3,7 @@ slug: why-your-team-needs-newsfeed title: 'Why your team needs a newsfeed' authors: johnnyreilly hide_table_of_contents: false +description: 'A newsfeed was built to narrow the gap between an online platform team and their users. It generates real-time stories in Markdown with links.' --- I'm part of a team that builds an online platform. I'm often preoccupied by how to narrow the gap between our users and "us" - the people that build the platform. It's important we understand how people use and interact with what we've built. If we don't then we're liable to waste our time and energy building the wrong things. Or the wrong amount of the right things. diff --git a/blog-website/blog/2020-10-02-autofac-6-integration-tests-and-generic-hosting/index.md b/blog-website/blog/2020-10-02-autofac-6-integration-tests-and-generic-hosting/index.md index 036249cc1d2..470d4e0dff9 100644 --- a/blog-website/blog/2020-10-02-autofac-6-integration-tests-and-generic-hosting/index.md +++ b/blog-website/blog/2020-10-02-autofac-6-integration-tests-and-generic-hosting/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [autofac, asp.net, Integration Testing] image: ./autofac-integration-tests.webp hide_table_of_contents: false +description: 'Integration tests using Autofac have been affected by a long-standing issue in .NET Core 3.0. Alternative approaches may not last long.' --- I [blogged a little while ago around to support integration tests using Autofac](../2020-05-21-autofac-webapplicationfactory-integration-tests/index.md). This was specific to Autofac but documented a workaround for a [long standing issue with `ConfigureTestContainer` that was introduced into .NET core 3.0](https://github.com/dotnet/aspnetcore/issues/14907) which affects [all third-party containers](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#default-service-container-replacement) that use `ConfigureTestContainer` in their tests. diff --git a/blog-website/blog/2020-10-19-safari-empty-download-content-type/index.md b/blog-website/blog/2020-10-19-safari-empty-download-content-type/index.md index fce5dcd0257..c7d9d88fce5 100644 --- a/blog-website/blog/2020-10-19-safari-empty-download-content-type/index.md +++ b/blog-website/blog/2020-10-19-safari-empty-download-content-type/index.md @@ -4,6 +4,7 @@ title: 'Safari: The Mysterious Case of the Empty Download' authors: johnnyreilly tags: [Safari] hide_table_of_contents: false +description: 'Safari requires a `Content-Type` header in responses to avoid empty downloads. Providing a `Content-Type` header resolved an authentication issue.' --- Safari wants a `Content-Type` header in responses. Even if the response is `Content-Length: 0`. Without this, Safari can attempt to trigger an empty download. Don't argue; just go with it; some browsers are strange. diff --git a/blog-website/blog/2020-10-31-azure-devops-node-api-git-api-getrefs-wiki-api/index.md b/blog-website/blog/2020-10-31-azure-devops-node-api-git-api-getrefs-wiki-api/index.md index 0c3462ea5cb..e800c5c5a8f 100644 --- a/blog-website/blog/2020-10-31-azure-devops-node-api-git-api-getrefs-wiki-api/index.md +++ b/blog-website/blog/2020-10-31-azure-devops-node-api-git-api-getrefs-wiki-api/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [azure devops, Node.js] image: ./title-image.png hide_table_of_contents: false +description: 'The Azure DevOps Node.js client library has limitations and missing features. Workarounds are possible for using Azure DevOps REST API directly.' --- The Azure DevOps Client library for Node.js has limitations and missing features, `IGitApi.getRefs` is missing pagination and `IWikiApi` is missing page create or update. This post details some of these issues and illustrates a workaround using the Azure DevOps REST API. @@ -239,7 +240,7 @@ export async function getRefs({ 'Failed to load refs', err?.message, err?.response?.status, - err?.response?.data + err?.response?.data, ); throw new Error('Failed to load refs'); } diff --git a/blog-website/blog/2020-11-10-throttle-data-requests-with-react-hooks/index.md b/blog-website/blog/2020-11-10-throttle-data-requests-with-react-hooks/index.md index 07e69c59d0c..e05471a7424 100644 --- a/blog-website/blog/2020-11-10-throttle-data-requests-with-react-hooks/index.md +++ b/blog-website/blog/2020-11-10-throttle-data-requests-with-react-hooks/index.md @@ -4,6 +4,7 @@ title: 'Throttling data requests with React Hooks' authors: johnnyreilly tags: [React] hide_table_of_contents: false +description: 'A custom React Hook `useThrottleRequests` is used to solve the problem of loading large amounts of data gradually and displaying loading progress.' --- When an application loads data, typically relatively few HTTP requests will be made. For example, if we imagine we're making a student administration application, then a "view" screen might make a single HTTP request to load that student's data before displaying it. @@ -104,11 +105,11 @@ function use10_000Requests(startedAt: string) { const results = await Promise.all( Array.from(Array(10_000)).map(async (_, index) => { const response = await fetch( - `/manifest.json?querystringValueToPreventCaching=${startedAt}_request-${index}` + `/manifest.json?querystringValueToPreventCaching=${startedAt}_request-${index}`, ); const json = await response.json(); return json; - }) + }), ); return results; @@ -185,7 +186,7 @@ export type RequestToMake = () => Promise; */ async function throttleRequests( requestsToMake: RequestToMake[], - maxParallelRequests = 6 + maxParallelRequests = 6, ) { // queue up simultaneous calls const queue: Promise[] = []; @@ -225,7 +226,7 @@ export type ThrottledProgress = { }; function createThrottledProgress( - totalRequests: number + totalRequests: number, ): ThrottledProgress { return { totalRequests, @@ -241,7 +242,7 @@ function createThrottledProgress( */ function updateThrottledProgress( currentProgress: ThrottledProgress, - newData: AsyncState + newData: AsyncState, ): ThrottledProgress { const errors = newData.error ? [...currentProgress.errors, newData.error] @@ -256,7 +257,7 @@ function updateThrottledProgress( ? 0 : Math.round( ((errors.length + values.length) / currentProgress.totalRequests) * - 100 + 100, ); const loading = @@ -293,7 +294,7 @@ type ThrottleActions = export function useThrottleRequests() { function reducer( throttledProgressAndState: ThrottledProgress, - action: ThrottleActions + action: ThrottleActions, ): ThrottledProgress { switch (action.type) { case 'initialise': @@ -315,7 +316,7 @@ export function useThrottleRequests() { const [throttle, dispatch] = useReducer( reducer, - createThrottledProgress(/** totalRequests */ 0) + createThrottledProgress(/** totalRequests */ 0), ); const updateThrottle = useMemo(() => { @@ -351,7 +352,7 @@ export function useThrottleRequests() { */ function queueRequests( requestsToMake: RequestToMake[], - maxParallelRequests = 6 + maxParallelRequests = 6, ) { dispatch({ type: 'initialise', @@ -414,7 +415,7 @@ function use10_000Requests(startedAt: string) { setProgressMessage(`loading ${index}...`); const response = await fetch( - `/manifest.json?querystringValueToPreventCaching=${startedAt}_request-${index}` + `/manifest.json?querystringValueToPreventCaching=${startedAt}_request-${index}`, ); const json = await response.json(); @@ -423,7 +424,7 @@ function use10_000Requests(startedAt: string) { console.error(`failed to load ${index}`, error); updateThrottle.requestFailedWithError(error); } - } + }, ); await updateThrottle.queueRequests(requestsToMake); @@ -551,7 +552,7 @@ function useContributors(contributorsUrlToLoad: string) { const requestsToMake = contributors.map(({ url }, index) => async () => { try { setProgressMessage( - `loading ${index} / ${contributors.length}: ${url}...` + `loading ${index} / ${contributors.length}: ${url}...`, ); const response = await fetch(url); @@ -585,11 +586,11 @@ function App() { const handleOwnerChange = useCallback( (event: React.ChangeEvent) => setOwner(event.target.value), - [setOwner] + [setOwner], ); const handleRepoChange = useCallback( (event: React.ChangeEvent) => setRepo(event.target.value), - [setRepo] + [setRepo], ); const contributorsUrl = `https://api.github.com/repos/${owner}/${repo}/contributors`; @@ -599,7 +600,7 @@ function App() { const bloggers = useMemo( () => throttle.values.filter((contributor) => contributor.blog), - [throttle] + [throttle], ); return ( diff --git a/blog-website/blog/2020-11-14-bulletproof-uniq-with-typescript/index.md b/blog-website/blog/2020-11-14-bulletproof-uniq-with-typescript/index.md index 91748aabd72..1372cb3a08b 100644 --- a/blog-website/blog/2020-11-14-bulletproof-uniq-with-typescript/index.md +++ b/blog-website/blog/2020-11-14-bulletproof-uniq-with-typescript/index.md @@ -4,6 +4,7 @@ title: 'Bulletproof uniq with TypeScript generics (yay code reviews!)' authors: johnnyreilly tags: [typescript] hide_table_of_contents: false +description: 'Code reviews provide opportunities for improvement. A developer shares how their colleagues comment led to the creation of a better “uniq” function.' --- Never neglect the possibilities of a code review. There are times when you raise a PR and all you want is for everyone to hit approve so you can merge, merge and ship, ship! This can be a missed opportunity. For as much as I'd like to imagine my code is perfect, it's patently not. There's always scope for improvement. @@ -78,7 +79,7 @@ I like compilers shouting at me. Or more accurately, I like compilers telling me * Return the unique values found in the passed iterable */ function uniq( - iterableToGetUniqueValuesOf: Iterable + iterableToGetUniqueValuesOf: Iterable, ) { return [...new Set(iterableToGetUniqueValuesOf)]; } diff --git a/blog-website/blog/2020-12-09-azure-pipelines-task-lib-and-isoutput-setvariable/index.md b/blog-website/blog/2020-12-09-azure-pipelines-task-lib-and-isoutput-setvariable/index.md index b19dd1b53f8..6dc2fc3e4c8 100644 --- a/blog-website/blog/2020-12-09-azure-pipelines-task-lib-and-isoutput-setvariable/index.md +++ b/blog-website/blog/2020-12-09-azure-pipelines-task-lib-and-isoutput-setvariable/index.md @@ -4,6 +4,7 @@ title: 'azure-pipelines-task-lib and isOutput setVariable' authors: johnnyreilly tags: [Azure Pipelines] hide_table_of_contents: false +description: 'This is a workaround for custom Azure Pipelines task extension to output variable since the library does not support "isOutput=true."' --- Some blog posts are insightful treatises on the future of web development, some are "here's how I solved my problem". This is most assuredly the latter. @@ -34,7 +35,7 @@ import * as os from 'os'; export function setOutputVariable( name: string, val: string, - secret = false + secret = false, ): void { // use the implementation of setVariable to set all the internals, // then subsequently set the output variable manually @@ -51,7 +52,7 @@ export function setOutputVariable( isOutput: 'true', issecret: (secret || false).toString(), }, - varValue + varValue, ); } diff --git a/blog-website/blog/2020-12-20-nullable-reference-types-csharp-strictnullchecks/index.md b/blog-website/blog/2020-12-20-nullable-reference-types-csharp-strictnullchecks/index.md index 31fac8a7e02..5156aaa9157 100644 --- a/blog-website/blog/2020-12-20-nullable-reference-types-csharp-strictnullchecks/index.md +++ b/blog-website/blog/2020-12-20-nullable-reference-types-csharp-strictnullchecks/index.md @@ -4,6 +4,7 @@ title: "Nullable reference types; CSharp's very own strictNullChecks" authors: johnnyreilly tags: [C#, nullable reference types] hide_table_of_contents: false +description: 'C# introduces nullable reference types similar to TypeScripts `strictNullChecks`. Enabling raises warnings and solves null reference risks.' --- 'Tis the season to play with new compiler settings! I'm a very keen TypeScript user and have been merrily using [`strictNullChecks`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#--strictnullchecks) since it shipped. I was dimly aware that C# was also getting a similar feature by the name of [nullable reference types](https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/nullable-reference-types). diff --git a/blog-website/blog/2020-12-21-how-to-make-azure-ad-403/index.md b/blog-website/blog/2020-12-21-how-to-make-azure-ad-403/index.md index 3403567aa31..d88a540eb81 100644 --- a/blog-website/blog/2020-12-21-how-to-make-azure-ad-403/index.md +++ b/blog-website/blog/2020-12-21-how-to-make-azure-ad-403/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Azure AD, ASP.NET] image: ./Forbidden.webp hide_table_of_contents: false +description: 'The `Microsoft.Identity.Web` library redirects to AccessDenied with a 302 (redirect) status code. Learn to return a 403 (forbidden) status code instead.' --- By default `Microsoft.Identity.Web` responds to unauthorized requests with a 302 (redirect). Do you want a 403 (forbidden) instead? Here's how. @@ -73,4 +74,4 @@ services.Configure(CookieAuthenticationDefaults.Aut }); ``` -So above, we check the request `Accept` headers and see if they contain `"text/html"`; which we're using as a signal that the request came from a users browsing. (This may not be bulletproof; better suggestions gratefully received.) If the request does contain a ` "text/html"``Accept ` header then we redirect the client to an `/unauthorized` screen, otherwise we return `403` as we did before. Super flexible and powerful! +So above, we check the request `Accept` headers and see if they contain `"text/html"`; which we're using as a signal that the request came from a users browsing. (This may not be bulletproof; better suggestions gratefully received.) If the request does contain a `"text/html"``Accept` header then we redirect the client to an `/unauthorized` screen, otherwise we return `403` as we did before. Super flexible and powerful! diff --git a/blog-website/blog/2020-12-22-prettier-your-csharp-with-dotnet-format-and-lint-staged/index.md b/blog-website/blog/2020-12-22-prettier-your-csharp-with-dotnet-format-and-lint-staged/index.md index 4f01cf32ce1..716adc379d0 100644 --- a/blog-website/blog/2020-12-22-prettier-your-csharp-with-dotnet-format-and-lint-staged/index.md +++ b/blog-website/blog/2020-12-22-prettier-your-csharp-with-dotnet-format-and-lint-staged/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./title-image.png tags: [Prettier] hide_table_of_contents: false +description: 'Standardise C# formatting with `dotnet format` and `lint-staged`. Customise formatting and integrate with `husky` in this guide.' --- Consistent formatting in a codebase is a good thing. We can achieve this in dotnet using `dotnet format`, used in combination with the npm packages `husky` and `lint-staged`. This post shows how. diff --git a/blog-website/blog/2020-12-30-azure-pipelines-meet-jest/index.md b/blog-website/blog/2020-12-30-azure-pipelines-meet-jest/index.md index f743c0873e9..cb21b30c699 100644 --- a/blog-website/blog/2020-12-30-azure-pipelines-meet-jest/index.md +++ b/blog-website/blog/2020-12-30-azure-pipelines-meet-jest/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./test-results.webp tags: [azure-pipelines, jest] hide_table_of_contents: false +description: 'Learn how to integrate Jest with Azure Pipelines to run tests as a part of your pipeline and utilize results reporting in the Azure Pipelines UI.' --- This post explains how to integrate the tremendous test runner [Jest](https://jestjs.io/) with the continuous integration platform [Azure Pipelines](https://azure.microsoft.com/en-gb/services/devops/pipelines/?nav=min). Perhaps we're setting up a new project and we've created a new React app with [Create React App](https://create-react-app.dev/). This ships with Jest support out of the box. How do we get that plugged into Pipelines such that: diff --git a/blog-website/blog/2021-01-02-create-react-app-with-ts-loader-and-craco/index.md b/blog-website/blog/2021-01-02-create-react-app-with-ts-loader-and-craco/index.md index 9530a8472c2..2f7606c0986 100644 --- a/blog-website/blog/2021-01-02-create-react-app-with-ts-loader-and-craco/index.md +++ b/blog-website/blog/2021-01-02-create-react-app-with-ts-loader-and-craco/index.md @@ -4,6 +4,7 @@ title: 'Create React App with ts-loader and CRACO' authors: johnnyreilly tags: [typescript, fork-ts-checker-webpack-plugin, ts-loader] hide_table_of_contents: false +description: 'Create React App now supports TypeScript with React, using Babel webpack loader or `ts-loader`. You can use CRACO to customize configurations.' --- [Create React App](https://create-react-app.dev/) is a fantastic way to get up and running building a web app with React. It also supports using TypeScript with React. Simply entering the following: @@ -65,14 +66,14 @@ module.exports = { configure: (webpackConfig, { paths }) => { const { hasFoundAny, matches } = getLoaders( webpackConfig, - loaderByName('babel-loader') + loaderByName('babel-loader'), ); if (!hasFoundAny) throwError('failed to find babel-loader'); console.log('removing babel-loader'); const { hasRemovedAny, removedCount } = removeLoaders( webpackConfig, - loaderByName('babel-loader') + loaderByName('babel-loader'), ); if (!hasRemovedAny) throwError('no babel-loader to remove'); if (removedCount !== 2) @@ -90,7 +91,7 @@ module.exports = { const { isAdded: tsLoaderIsAdded } = addAfterLoader( webpackConfig, loaderByName('url-loader'), - tsLoader + tsLoader, ); if (!tsLoaderIsAdded) throwError('failed to add ts-loader'); console.log('added ts-loader'); @@ -99,7 +100,7 @@ module.exports = { const { isAdded: babelLoaderIsAdded } = addAfterLoader( webpackConfig, loaderByName('ts-loader'), - matches[1].loader // babel-loader + matches[1].loader, // babel-loader ); if (!babelLoaderIsAdded) throwError('failed to add back babel-loader for non-application JS'); diff --git a/blog-website/blog/2021-01-03-strongly-typing-react-query-s-usequeries/index.md b/blog-website/blog/2021-01-03-strongly-typing-react-query-s-usequeries/index.md index 7c688ef6082..cac6c6ca184 100644 --- a/blog-website/blog/2021-01-03-strongly-typing-react-query-s-usequeries/index.md +++ b/blog-website/blog/2021-01-03-strongly-typing-react-query-s-usequeries/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./strongly-typing-usequeries.webp tags: [useQueries, react-query] hide_table_of_contents: false +description: 'Learn how to strongly type `useQueries` in `react-query` with `useQueriesTyped`. A wrapper function provides the strongly-typed API.' --- `react-query` has a weakly typed hook named `useQueries`. It's possible to turn that into a strong typed hook; this post shows you how. @@ -33,7 +34,7 @@ function App({ users }) { queryKey: ['user', user.id], queryFn: () => fetchUserById(user.id), }; - }) + }), ); } ``` @@ -49,7 +50,7 @@ This returns an array of [`UseQueryResult`](https://github.com/tannerlinsley/rea ```ts export type UseQueryResult< TData = unknown, - TError = unknown + TError = unknown, > = UseBaseQueryResult; ``` @@ -67,7 +68,7 @@ import { useQueries, UseQueryOptions, UseQueryResult } from 'react-query'; type Awaited = T extends PromiseLike ? Awaited : T; export function useQueriesTyped( - queries: [...TQueries] + queries: [...TQueries], ): { [ArrayElement in keyof TQueries]: UseQueryResult< TQueries[ArrayElement] extends { select: infer TSelect } @@ -85,7 +86,7 @@ export function useQueriesTyped( } { // eslint-disable-next-line @typescript-eslint/no-explicit-any return useQueries( - queries as UseQueryOptions[] + queries as UseQueryOptions[], ) as any; } ``` @@ -236,7 +237,7 @@ Well, supplying `queryFn`s with different signatures looks like this: ```ts const result = useQueriesTyped( { queryKey: 'key1', queryFn: () => 1 }, - { queryKey: 'key2', queryFn: () => 'two' } + { queryKey: 'key2', queryFn: () => 'two' }, ); // const result: [QueryObserverResult, QueryObserverResult] @@ -254,7 +255,7 @@ Next let's look at a `.map` example with identical types in our supplied array: ```ts const resultWithAllTheSameTypes = useQueriesTyped( - ...[1, 2].map((x) => ({ queryKey: `${x}`, queryFn: () => x })) + ...[1, 2].map((x) => ({ queryKey: `${x}`, queryFn: () => x })), ); // const resultWithAllTheSameTypes: QueryObserverResult[] @@ -269,7 +270,10 @@ Finally let's look at how `.map` handles arrays with different types of elements ```ts const resultWithDifferentTypes = useQueriesTyped( - ...[1, 'two', new Date()].map((x) => ({ queryKey: `${x}`, queryFn: () => x })) + ...[1, 'two', new Date()].map((x) => ({ + queryKey: `${x}`, + queryFn: () => x, + })), ); //const resultWithDifferentTypes: QueryObserverResult[] diff --git a/blog-website/blog/2021-01-14-azure-easy-auth-and-roles-with-dotnet-and-core/index.md b/blog-website/blog/2021-01-14-azure-easy-auth-and-roles-with-dotnet-and-core/index.md index 6d751250768..ca39219149f 100644 --- a/blog-website/blog/2021-01-14-azure-easy-auth-and-roles-with-dotnet-and-core/index.md +++ b/blog-website/blog/2021-01-14-azure-easy-auth-and-roles-with-dotnet-and-core/index.md @@ -4,6 +4,7 @@ title: 'Azure App Service, Easy Auth and Roles with .NET' authors: johnnyreilly tags: [Azure, authorization, authentication, easy auth] hide_table_of_contents: false +description: '"Easy Auth" in Azure App Service doesnt currently work with .NET Core and .NET due to discrepancies. Open-source middleware can help solve the issue.' --- Azure App Service has a feature which is intended to allow Authentication and Authorization to be applied outside of your application code. It's called ["Easy Auth"](https://docs.microsoft.com/en-us/azure/app-service/overview-authentication-authorization). Unfortunately, in the context of App Services it doesn't work with .NET Core and .NET. Perhaps it would be better to say: of the various .NETs, it supports .NET Framework. [To quote the docs](https://docs.microsoft.com/en-us/azure/app-service/overview-authentication-authorization#userapplication-claims): diff --git a/blog-website/blog/2021-01-17-azure-easy-auth-and-roles-with-net-and-microsoft-identity-web/index.md b/blog-website/blog/2021-01-17-azure-easy-auth-and-roles-with-net-and-microsoft-identity-web/index.md index 4cbeb95c0b5..7a971e28de6 100644 --- a/blog-website/blog/2021-01-17-azure-easy-auth-and-roles-with-net-and-microsoft-identity-web/index.md +++ b/blog-website/blog/2021-01-17-azure-easy-auth-and-roles-with-net-and-microsoft-identity-web/index.md @@ -4,6 +4,7 @@ title: 'Azure App Service, Easy Auth and Roles with .NET and Microsoft.Identity. authors: johnnyreilly tags: [Azure, easy auth, ASP.NET, authorization] hide_table_of_contents: false +description: 'The `Microsoft.Identity.Web` library has authorization issues with roles. A `IClaimsTransformation` can map claims to fix the problem.' --- [I wrote recently about how to get Azure App Service Easy Auth to work with roles](../2021-01-14-azure-easy-auth-and-roles-with-dotnet-and-core/index.md). This involved borrowing the approach used by [MaximeRouiller.Azure.AppService.EasyAuth](https://github.com/MaximRouiller/MaximeRouiller.Azure.AppService.EasyAuth). diff --git a/blog-website/blog/2021-01-29-surfacing-azure-pipelines-build-info-in-an-aspnet-react-app/index.md b/blog-website/blog/2021-01-29-surfacing-azure-pipelines-build-info-in-an-aspnet-react-app/index.md index c9e95a5014d..b5b867d7467 100644 --- a/blog-website/blog/2021-01-29-surfacing-azure-pipelines-build-info-in-an-aspnet-react-app/index.md +++ b/blog-website/blog/2021-01-29-surfacing-azure-pipelines-build-info-in-an-aspnet-react-app/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./about-page.png tags: [azure pipelines] hide_table_of_contents: false +description: 'Surface build metadata using Azure Pipelines and ASP.NET for both client and server builds in your app with this tutorial.' --- How do you answer the question: "what version of my application is running in Production right now?" This post demonstrates how to surface the build metadata that represents the version of your app, from your app using Azure Pipelines and ASP.NET. @@ -203,7 +204,7 @@ const useStyles = (cardColor: string) => main: { padding: theme.spacing(2), }, - }) + }), )(); type Styles = ReturnType; diff --git a/blog-website/blog/2021-01-30-aspnet-serilog-and-application-insights/index.md b/blog-website/blog/2021-01-30-aspnet-serilog-and-application-insights/index.md index 339cedc96b9..dacdbc16acd 100644 --- a/blog-website/blog/2021-01-30-aspnet-serilog-and-application-insights/index.md +++ b/blog-website/blog/2021-01-30-aspnet-serilog-and-application-insights/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./title-image.png tags: [asp.net, Azure, Application Insights, Serilog] hide_table_of_contents: false +description: 'Learn how to integrate Serilog into Azures Application Insights for better diagnostic logging by following these steps and adding dependencies.' --- If you're deploying an ASP.NET application to Azure App Services / Azure Container Apps or similar, there's a decent chance you'll also be using the fantastic [Serilog](https://serilog.net/) and will want to plug it into Azure's [Application Insights](https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview). diff --git a/blog-website/blog/2021-02-08-arm-templates-security-role-assignments/index.md b/blog-website/blog/2021-02-08-arm-templates-security-role-assignments/index.md index 05ee2ad459c..cb1b108f7e9 100644 --- a/blog-website/blog/2021-02-08-arm-templates-security-role-assignments/index.md +++ b/blog-website/blog/2021-02-08-arm-templates-security-role-assignments/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./with-great-power-comes-great-responsibility.webp tags: [Azure, ARM templates, role assignments, permissions] hide_table_of_contents: false +description: 'ARM templates can help define Azure Role-Based Access Control. By creating role assignments, users can grant Managed Identities access to resources.' --- This post is about Azure's role assignments and ARM templates. Role assignments can be thought of as "permissions for Azure". diff --git a/blog-website/blog/2021-02-11-azure-app-service-health-checks-and-zero-downtime-deployments/index.md b/blog-website/blog/2021-02-11-azure-app-service-health-checks-and-zero-downtime-deployments/index.md index 9aae5ff57ef..739a11d5ff8 100644 --- a/blog-website/blog/2021-02-11-azure-app-service-health-checks-and-zero-downtime-deployments/index.md +++ b/blog-website/blog/2021-02-11-azure-app-service-health-checks-and-zero-downtime-deployments/index.md @@ -4,6 +4,7 @@ title: 'Azure App Service, Health checks and zero downtime deployments' authors: johnnyreilly tags: [Azure App Service] hide_table_of_contents: false +description: 'Azure App Service enables zero downtime deployments using health checks and deployment slots. Automated swapping slots ensure constant service.' --- I've been working recently on zero downtime deployments using Azure App Service. They're facilitated by a combination of [Health checks](https://docs.microsoft.com/en-us/azure/app-service/monitor-instances-health-check) and [deployment slots](https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots). This post will talk about why this is important and how it works. diff --git a/blog-website/blog/2021-02-16-easy-auth-tokens-survive-releases-on-linux-azure-app-service/index.md b/blog-website/blog/2021-02-16-easy-auth-tokens-survive-releases-on-linux-azure-app-service/index.md index eb070071790..409de72b83e 100644 --- a/blog-website/blog/2021-02-16-easy-auth-tokens-survive-releases-on-linux-azure-app-service/index.md +++ b/blog-website/blog/2021-02-16-easy-auth-tokens-survive-releases-on-linux-azure-app-service/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly image: ./easy-auth-zero-downtime-deployment.webp tags: [Azure, easy auth, ASP.NET, authorization] hide_table_of_contents: false +description: 'To prevent authentication issues during restarts or deployments, Microsoft is recommending Blob Storage for Token Cache to store and fetch tokens.' --- I [wrote recently about zero downtime deployments on Azure App Service](../2021-02-11-azure-app-service-health-checks-and-zero-downtime-deployments/index.md). Many applications require authentication, and ours is no exception. In our case we're using Azure Active Directory facilitated by ["Easy Auth"](https://docs.microsoft.com/en-us/azure/app-service/overview-authentication-authorization) which provides authentication to our App Service. diff --git a/blog-website/blog/2021-03-06-generate-typescript-and-csharp-clients-with-nswag/index.md b/blog-website/blog/2021-03-06-generate-typescript-and-csharp-clients-with-nswag/index.md index 303c152b821..7bd5da5a3cf 100644 --- a/blog-website/blog/2021-03-06-generate-typescript-and-csharp-clients-with-nswag/index.md +++ b/blog-website/blog/2021-03-06-generate-typescript-and-csharp-clients-with-nswag/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [NSwag, Swagger, open-api, typescript, C#] image: ./use-generated-client.gif hide_table_of_contents: false +description: 'NSwag simplifies APIs by auto-generating OpenAPI specs and clients. Learn to create TypeScript clients from NSwag using a .NET console app.' --- Generating clients for APIs is a tremendous way to reduce the amount of work you have to do when you're building a project. Why handwrite that code when it can be auto-generated for you quickly and accurately by a tool like [NSwag](https://github.com/RicoSuter/NSwag)? To quote the docs: diff --git a/blog-website/blog/2021-03-10-managed-identity-azure-sql-entity-framework/index.md b/blog-website/blog/2021-03-10-managed-identity-azure-sql-entity-framework/index.md index fbd90b1234a..f220c3020b5 100644 --- a/blog-website/blog/2021-03-10-managed-identity-azure-sql-entity-framework/index.md +++ b/blog-website/blog/2021-03-10-managed-identity-azure-sql-entity-framework/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [connection string, managed identity, entity framework] image: ./entity-framework-core-nuget.png hide_table_of_contents: false +description: 'Managed Identity provides secure, developer-friendly access to Azure SQL databases without the need for usernames and passwords.' --- Managed Identity offers a very secure way for applications running in Azure to connect to Azure SQL databases. It's an approach that does not require code changes; merely configuration of connection string and associated resources. Hence it has a good developer experience. Importantly, it allows us to avoid exposing our database to username / password authentication, and hence making it a tougher target for bad actors. diff --git a/blog-website/blog/2021-03-15-definitive-guide-to-migrating-from-blogger-to-docusaurus/index.md b/blog-website/blog/2021-03-15-definitive-guide-to-migrating-from-blogger-to-docusaurus/index.md index 7b9099272be..43c93780834 100644 --- a/blog-website/blog/2021-03-15-definitive-guide-to-migrating-from-blogger-to-docusaurus/index.md +++ b/blog-website/blog/2021-03-15-definitive-guide-to-migrating-from-blogger-to-docusaurus/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Blogger, Docusaurus, typescript] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to transfer a Blogger website to Docusaurus without losing content. Use a TypeScript console app to convert HTML to Markdown.' --- This post documents how to migrate a blog from Blogger to Docusaurus. @@ -142,7 +143,7 @@ async function makePostsFromXML() { if (notMarkdownable.length) console.log( 'These blog posts could not be turned into MarkDown - go find out why!', - notMarkdownable + notMarkdownable, ); } @@ -178,7 +179,7 @@ async function makeAuthorsYml(directory: string) { await fs.promises.writeFile( path.join(directory, 'authors.yml'), authorsYml, - 'utf-8' + 'utf-8', ); } @@ -212,13 +213,13 @@ async function getPosts(): Promise { entry.category.some( (category: any) => category.attr['@_term'] === - 'http://schemas.google.com/blogger/2008/kind#post' + 'http://schemas.google.com/blogger/2008/kind#post', ) && entry.link.some( (link: any) => - link.attr['@_href'] && link.attr['@_type'] === 'text/html' + link.attr['@_href'] && link.attr['@_type'] === 'text/html', ) && - entry.published < '2021-03-07' + entry.published < '2021-03-07', ); const posts: Post[] = postsRaw.map((entry: any) => { @@ -228,25 +229,25 @@ async function getPosts(): Promise { published: entry.published, link: entry.link.find( (link: any) => - link.attr['@_href'] && link.attr['@_type'] === 'text/html' + link.attr['@_href'] && link.attr['@_type'] === 'text/html', ) ? entry.link.find( (link: any) => - link.attr['@_href'] && link.attr['@_type'] === 'text/html' + link.attr['@_href'] && link.attr['@_type'] === 'text/html', ).attr['@_href'] : undefined, tags: Array.isArray(entry.category) && entry.category.some( (category: any) => - category.attr['@_scheme'] === 'http://www.blogger.com/atom/ns#' + category.attr['@_scheme'] === 'http://www.blogger.com/atom/ns#', ) ? entry.category .filter( (category: any) => category.attr['@_scheme'] === 'http://www.blogger.com/atom/ns#' && - category.attr['@_term'] !== 'constructor' + category.attr['@_term'] !== 'constructor', ) // 'constructor' will make docusaurus choke .map((category: any) => category.attr['@_term']) : [], @@ -323,7 +324,7 @@ async function makePostIntoMarkDownAndDownloadImages(post: Post) { .replace( /\[!\[null\]\(<(.*?)\].*?>\)/g, (match) => - `![](${match.slice(match.indexOf('<') + 1, match.indexOf('>'))})\n\n` + `![](${match.slice(match.indexOf('<') + 1, match.indexOf('>'))})\n\n`, ) // Blogger tends to put images in HTML that looks like this: @@ -341,7 +342,7 @@ async function makePostIntoMarkDownAndDownloadImages(post: Post) { if (src) images.push(src); return `![${alt}](${src})`; - } + }, ); } catch (e) { console.log(post.link); @@ -370,7 +371,7 @@ ${markdown} await fs.promises.writeFile( path.resolve(docusaurusDirectory, 'blog', blogdirPath, 'index.md'), - content + content, ); } diff --git a/blog-website/blog/2021-03-17-rss-update-we-moved-to-docusaurus/index.md b/blog-website/blog/2021-03-17-rss-update-we-moved-to-docusaurus/index.md index 0f677b55839..19426500d0c 100644 --- a/blog-website/blog/2021-03-17-rss-update-we-moved-to-docusaurus/index.md +++ b/blog-website/blog/2021-03-17-rss-update-we-moved-to-docusaurus/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Blogger, Docusaurus, RSS, Atom] image: ./rss.png hide_table_of_contents: false +description: 'A blogger migrated to Docusaurus and GitHub Pages, shares feed updates, with new Atom and RSS feeds and all historic links still working.' --- My blog lived happily on [Blogger](https://icanmakethiswork.blogspot.com/) for the past decade. It's now built with [Docusaurus](https://v2.docusaurus.io/) and hosted on [GitHub Pages](https://pages.github.com/). To understand the why, [read my last post](../2021-03-15-definitive-guide-to-migrating-from-blogger-to-docusaurus/index.md). This post serves purely to share details of feed updates for RSS / Atom subscribers. diff --git a/blog-website/blog/2021-03-20-bicep-meet-azure-pipelines/index.md b/blog-website/blog/2021-03-20-bicep-meet-azure-pipelines/index.md index 8a582ecf41c..768de642f4c 100644 --- a/blog-website/blog/2021-03-20-bicep-meet-azure-pipelines/index.md +++ b/blog-website/blog/2021-03-20-bicep-meet-azure-pipelines/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Bicep, ARM templates, Azure Pipelines, Azure CLI] image: ./bicep-meet-azure-pipelines.webp hide_table_of_contents: false +description: 'Bicep is a more readable alternative to ARM templates. Though no Bicep task is available yet, Azure CLI can still deploy Bicep.' --- [Bicep](https://github.com/Azure/bicep) is a terser and more readable alternative language to ARM templates. Running ARM templates in Azure Pipelines is straightforward. However, there isn't yet a first class experience for running Bicep in Azure Pipelines. This post demonstrates an approach that can be used until a Bicep task is available. diff --git a/blog-website/blog/2021-03-23-bicep-meet-azure-pipelines-2/index.md b/blog-website/blog/2021-03-23-bicep-meet-azure-pipelines-2/index.md index 43ff529ced2..6ffcfd4e523 100644 --- a/blog-website/blog/2021-03-23-bicep-meet-azure-pipelines-2/index.md +++ b/blog-website/blog/2021-03-23-bicep-meet-azure-pipelines-2/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Bicep, ARM templates, Azure Pipelines, Azure CLI] image: ./bicep-meet-azure-pipelines.webp hide_table_of_contents: false +description: 'With Azure CLI, Bicep can be run in Azure Pipeline with minimal effort. Compile Bicep to ARM in a simple one-liner bash step.' --- [Last time](../2021-03-20-bicep-meet-azure-pipelines/index.md) I wrote about how to use the Azure CLI to run Bicep within the context of an Azure Pipeline. The solution was relatively straightforward, and involved using `az deployment group create` in a task. There's an easier way. diff --git a/blog-website/blog/2021-04-10-hello-world-bicep/index.md b/blog-website/blog/2021-04-10-hello-world-bicep/index.md index ada7210ff8b..507953e53d4 100644 --- a/blog-website/blog/2021-04-10-hello-world-bicep/index.md +++ b/blog-website/blog/2021-04-10-hello-world-bicep/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Bicep, ARM templates] image: ./hello-world-bicep.webp hide_table_of_contents: false +description: 'Bicep simplifies Azure Resource Management through concise syntax. The "Hello World" example highlights how Bicep outperforms ARM templates.' --- Bicep makes Azure Resource Management a great deal simpler than ARM templates. The selling point here is grokkability. This post takes a look at the ["Hello World" example recently added to the Bicep repo](https://github.com/Azure/bicep/pull/2011) to appreciate quite what a difference it makes. diff --git a/blog-website/blog/2021-04-20-ts-loader-goes-webpack-5/index.md b/blog-website/blog/2021-04-20-ts-loader-goes-webpack-5/index.md index 543158a9abf..4604c92b13c 100644 --- a/blog-website/blog/2021-04-20-ts-loader-goes-webpack-5/index.md +++ b/blog-website/blog/2021-04-20-ts-loader-goes-webpack-5/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [webpack, ts-loader, typescript] image: ./ts-loader-9.png hide_table_of_contents: false +description: 'TypeScript webpack loader `ts-loader` has released version 9.0.0, with support for webpack 5 and a minimum supported Node version of 12.' --- `ts-loader` has just released [v9.0.0](https://github.com/TypeStrong/ts-loader/releases/tag/v9.0.0). This post goes through what this release is all about, and what it took to ship this version. For intrigue, it includes a brief scamper into my mental health along the way. Some upgrades go smoothly - this one had some hiccups. But we'll get into that. diff --git a/blog-website/blog/2021-04-24-service-now-api-and-typescript-conditional-types/index.md b/blog-website/blog/2021-04-24-service-now-api-and-typescript-conditional-types/index.md index e01a6acebbc..0a9f0945ac1 100644 --- a/blog-website/blog/2021-04-24-service-now-api-and-typescript-conditional-types/index.md +++ b/blog-website/blog/2021-04-24-service-now-api-and-typescript-conditional-types/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Service Now, typescript] image: ./ts-ervice-now.png hide_table_of_contents: false +description: 'Learn how to model ServiceNow REST API results using TypeScript conditional types to minimise repetition and remain strongly typed.' --- The [Service Now REST API](https://docs.servicenow.com/bundle/paris-application-development/page/build/applications/concept/api-rest.html) is an API which allows you to interact with Service Now. It produces different shaped results based upon the [`sysparm_display_value` query parameter](https://docs.servicenow.com/bundle/paris-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html#c_TableAPI__table-GET). This post looks at how we can model these API results with TypeScripts conditional types. The aim being to minimise repetition whilst remaining strongly typed. This post is specifically about the Service Now API, but the principles around conditional type usage are generally applicable. @@ -143,7 +144,7 @@ Now we're going to create our first conditional type: export type PropertyValue< TAllTrueFalse extends DisplayValue, TValue = string, - TDisplayValue = string + TDisplayValue = string, > = TAllTrueFalse extends 'all' ? ValueAndDisplayValue : TAllTrueFalse extends 'true' diff --git a/blog-website/blog/2021-05-01-blog-archive-for-docusaurus/index.md b/blog-website/blog/2021-05-01-blog-archive-for-docusaurus/index.md index 22ee7a40a8c..fe7d4eb0b49 100644 --- a/blog-website/blog/2021-05-01-blog-archive-for-docusaurus/index.md +++ b/blog-website/blog/2021-05-01-blog-archive-for-docusaurus/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Docusaurus, webpack] image: ./docusaurus-blog-archive.png hide_table_of_contents: false +description: 'Learn how to add a blog archive to your Docusaurus blog and browse through historic posts. Follow the articles steps to implement.' --- Docusaurus doesn't ship with "blog archive" functionality. By which I mean, something that allows you to look at an overview of your historic blog posts. It turns out it is fairly straightforward to implement your own. This post does just that. @@ -84,7 +85,7 @@ const allPosts = ((ctx) => { }, ]; }, - /** @type {string[]}>} */ [] + /** @type {string[]}>} */ [], ); })(require.context('../../blog', true, /index.md/)); ``` @@ -119,7 +120,7 @@ Now we're ready to blast it onto the screen. We'll create two components: ```tsx function Year( - /** @type {{ year: string; posts: BlogPost[]; }} */ { year, posts } + /** @type {{ year: string; posts: BlogPost[]; }} */ { year, posts }, ) { return (
@@ -208,7 +209,7 @@ const allPosts = ((ctx) => { }, ]; }, - /** @type {BlogPost[]}>} */ [] + /** @type {BlogPost[]}>} */ [], ); // @ts-ignore })(require.context('../../blog', true, /index.md/)); @@ -225,7 +226,7 @@ const yearsOfPosts = Array.from(postsByYear, ([year, posts]) => ({ })); function Year( - /** @type {{ year: string; posts: BlogPost[]; }} */ { year, posts } + /** @type {{ year: string; posts: BlogPost[]; }} */ { year, posts }, ) { return (
diff --git a/blog-website/blog/2021-05-08-create-pipeline-with-azure-devops-api/index.md b/blog-website/blog/2021-05-08-create-pipeline-with-azure-devops-api/index.md index adb2494da70..b0f99313f5a 100644 --- a/blog-website/blog/2021-05-08-create-pipeline-with-azure-devops-api/index.md +++ b/blog-website/blog/2021-05-08-create-pipeline-with-azure-devops-api/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Azure Pipelines, azure devops] image: ./new-pipeline.webp hide_table_of_contents: false +description: 'Learn how to create an Azure Pipeline using the Azure DevOps REST API with a personal access token and JSON file, as detailed in this post.' --- Creating an Azure Pipeline using the Azure DevOps REST API is possible, but badly documented. This post goes through how to do this. diff --git a/blog-website/blog/2021-05-15-azurite-and-table-storage-dev-container/index.md b/blog-website/blog/2021-05-15-azurite-and-table-storage-dev-container/index.md index d7e812920c0..706ef8f7729 100644 --- a/blog-website/blog/2021-05-15-azurite-and-table-storage-dev-container/index.md +++ b/blog-website/blog/2021-05-15-azurite-and-table-storage-dev-container/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [VS Code, devcontainer, Docker] image: ./dev-container-start.gif hide_table_of_contents: false +description: 'Learn to use Azurite v3 in a dev container to access the Table Storage API in preview for local development without a real database.' --- It's great to be able to develop locally without needing a "real" database to connect to. [Azurite](https://github.com/Azure/Azurite) is an Azure Storage emulator which exists to support just that. This post demonstrates how to run Azurite v3 in a [dev container](https://code.visualstudio.com/docs/remote/containers), such that you can access the Table Storage API, which is currently in preview. diff --git a/blog-website/blog/2021-06-30-react-18-and-typescript/index.md b/blog-website/blog/2021-06-30-react-18-and-typescript/index.md index a427ad6657a..057a52d4a8a 100644 --- a/blog-website/blog/2021-06-30-react-18-and-typescript/index.md +++ b/blog-website/blog/2021-06-30-react-18-and-typescript/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [React, typescript, React 18] image: ./createNode-error.png hide_table_of_contents: false +description: 'Upgrade React to `@next` and add new type definitions to use React 18 alpha with TypeScript. Use `ReactDOM.createRoot` API.' --- [React 18 alpha has been released](https://reactjs.org/blog/2021/06/08/the-plan-for-react-18.html); but can we use it with TypeScript? The answer is "yes", but you need to do a couple of things to make that happen. This post will show you what to do. diff --git a/blog-website/blog/2021-07-01-c-sharp-9-azure-functions-in-process/index.md b/blog-website/blog/2021-07-01-c-sharp-9-azure-functions-in-process/index.md index e96c5b26e35..51c6677c978 100644 --- a/blog-website/blog/2021-07-01-c-sharp-9-azure-functions-in-process/index.md +++ b/blog-website/blog/2021-07-01-c-sharp-9-azure-functions-in-process/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [C#, Azure Functions, .NET] image: ./title-image.png hide_table_of_contents: false +description: 'Learn to use C# 9 with .NET Core 3.1 Azure Functions in this step-by-step guide by adding new elements to your .csproj file.' --- C# 9 has some amazing features. Azure Functions are have two modes: isolated and in-process. Whilst isolated supports .NET 5 (and hence C# 9), in-process supports .NET Core 3.1 (C# 8). This post shows how we can use C# 9 with in-process Azure Functions running on .NET Core 3.1. @@ -73,9 +74,7 @@ There's a [great post on Reddit addressing using C# 9 with .NET Core 3.1 which s > However, there are three categories of features in C#: > > 1. features that are entirely part of the compiler. Those will work. -> > 2. features that require BCL additions. Since you're on the older BCL, those will need to be backported. For example, to use init; and record, you can use https://github.com/manuelroemer/IsExternalInit. -> > 3. features that require runtime additions. Those cannot be added at all. For example, default interface members in C# 8, and covariant return types in C# 9. Of the above, 1 and 2 add a tremendous amount of value. The features of 3 are great, but more niche. Speaking personally, I care a great deal about [Record types](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#record-types). So let's apply this. diff --git a/blog-website/blog/2021-07-07-output-connection-strings-and-keys-from-azure-bicep/index.md b/blog-website/blog/2021-07-07-output-connection-strings-and-keys-from-azure-bicep/index.md index 9103ead3c58..dcf87ff0c41 100644 --- a/blog-website/blog/2021-07-07-output-connection-strings-and-keys-from-azure-bicep/index.md +++ b/blog-website/blog/2021-07-07-output-connection-strings-and-keys-from-azure-bicep/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Bicep, Azure, connection string] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to acquire connection strings and access keys in Azure with Bicep using the `listKeys` helper, and optionally consume them in Azure Pipelines.' --- If we're provisioning resources in Azure with Bicep, we may have a need to acquire the connection strings and keys of our newly deployed infrastructure. For example, the connection strings of an event hub or the access keys of a storage account. Perhaps we'd like to use them to run an end-to-end test, perhaps we'd like to store these secrets somewhere for later consumption. This post shows how to do that using Bicep and the `listKeys` helper. Optionally it shows how we could consume this in Azure Pipelines. diff --git a/blog-website/blog/2021-07-11-webpack-esbuild-why-not-both/index.md b/blog-website/blog/2021-07-11-webpack-esbuild-why-not-both/index.md index 85edbeeb7d6..296a541ffdc 100644 --- a/blog-website/blog/2021-07-11-webpack-esbuild-why-not-both/index.md +++ b/blog-website/blog/2021-07-11-webpack-esbuild-why-not-both/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [webpack, esbuild, ts-loader, babel-loader] image: ./webpack-esbuild-why-not-both.webp hide_table_of_contents: false +description: 'Using both webpack and esbuild for faster builds is possible with esbuild-loader. This post guides through using it with webpack and migrating to it.' --- Builds can be made faster using tools like [esbuild](https://github.com/evanw/esbuild). However, if you're invested in [webpack](https://github.com/webpack/webpack) but would still like to take advantage of speedier builds, there is a way. This post takes us through using esbuild alongside webpack using [esbuild-loader](https://github.com/privatenumber/esbuild-loader). @@ -148,14 +149,14 @@ module.exports = { configure: (webpackConfig, { paths }) => { const { hasFoundAny, matches } = getLoaders( webpackConfig, - loaderByName('babel-loader') + loaderByName('babel-loader'), ); if (!hasFoundAny) throwError('failed to find babel-loader'); console.log('removing babel-loader'); const { hasRemovedAny, removedCount } = removeLoaders( webpackConfig, - loaderByName('babel-loader') + loaderByName('babel-loader'), ); if (!hasRemovedAny) throwError('no babel-loader to remove'); if (removedCount !== 2) @@ -176,7 +177,7 @@ module.exports = { const { isAdded: tsLoaderIsAdded } = addAfterLoader( webpackConfig, loaderByName('url-loader'), - tsLoader + tsLoader, ); if (!tsLoaderIsAdded) throwError('failed to add esbuild-loader'); console.log('added esbuild-loader'); @@ -185,7 +186,7 @@ module.exports = { const { isAdded: babelLoaderIsAdded } = addAfterLoader( webpackConfig, loaderByName('esbuild-loader'), - matches[1].loader // babel-loader + matches[1].loader, // babel-loader ); if (!babelLoaderIsAdded) throwError('failed to add back babel-loader for non-application JS'); diff --git a/blog-website/blog/2021-07-14-directory-build-props-c-sharp-9-for-all/index.md b/blog-website/blog/2021-07-14-directory-build-props-c-sharp-9-for-all/index.md index 2d2c75c5027..bbaaca49a34 100644 --- a/blog-website/blog/2021-07-14-directory-build-props-c-sharp-9-for-all/index.md +++ b/blog-website/blog/2021-07-14-directory-build-props-c-sharp-9-for-all/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Directory.Build.props, C#, .NET] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to use C# 9 with .NET Core by creating a `Directory.Build.props` file. All projects in the solution will support C#9 with no further steps.' --- .NET Core can make use of C# 9 by making some changes to your `.csproj` files. There is a way to opt all projects in a solution into this behaviour in a _single_ place, through using a `Directory.Build.props` file and / or a `Directory.Build.targets` file. Here's how to do it. diff --git a/blog-website/blog/2021-08-01-typescript-abstract-classes-and-constructors/index.md b/blog-website/blog/2021-08-01-typescript-abstract-classes-and-constructors/index.md index 45eac373a58..e97fa4feaf0 100644 --- a/blog-website/blog/2021-08-01-typescript-abstract-classes-and-constructors/index.md +++ b/blog-website/blog/2021-08-01-typescript-abstract-classes-and-constructors/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [typescript] image: ./vs-code-abstract-screenshot.png hide_table_of_contents: false +description: 'TypeScript abstract classes cannot be directly instantiated, but only used as a base for non-abstract subclasses with specific constructor usage rules.' --- TypeScript has the ability to define classes as abstract. This means they cannot be instantiated directly, only non-abstract subclasses can be. Let's take a look at what this means when it comes to constructor usage. diff --git a/blog-website/blog/2021-08-14-typescript-4-4-more-readable-code/index.md b/blog-website/blog/2021-08-14-typescript-4-4-more-readable-code/index.md index 0f0bf19c49a..584c1ebbdca 100644 --- a/blog-website/blog/2021-08-14-typescript-4-4-more-readable-code/index.md +++ b/blog-website/blog/2021-08-14-typescript-4-4-more-readable-code/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [typescript] image: ./reactions-on-github.webp hide_table_of_contents: false +description: 'TypeScript 4.4 introduces "Control Flow Analysis of Aliased Conditions" which improves code readability by more expressive and less repetitive code.' --- An exciting feature is shipping with TypeScript 4.4. It has the name ["Control Flow Analysis of Aliased Conditions"](https://devblogs.microsoft.com/typescript/announcing-typescript-4-4-beta/#cfa-aliased-conditions) which is quite a mouthful. This post unpacks what this feature is, and demonstrates the contribution it makes to improving the readability of code. diff --git a/blog-website/blog/2021-08-15-bicep-azure-static-web-apps-azure-devops/index.md b/blog-website/blog/2021-08-15-bicep-azure-static-web-apps-azure-devops/index.md index 1d175f3ec53..cf0c6acbc6d 100644 --- a/blog-website/blog/2021-08-15-bicep-azure-static-web-apps-azure-devops/index.md +++ b/blog-website/blog/2021-08-15-bicep-azure-static-web-apps-azure-devops/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Azure Static Web Apps, Bicep, azure devops, Azure Pipelines] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to deploy Azure Static Web Apps using Bicep and Azure DevOps, including workarounds for common deployment issues.' --- This post demonstrates how to deploy [Azure Static Web Apps](https://docs.microsoft.com/en-us/azure/static-web-apps/overview) using Bicep and Azure DevOps. It includes a few workarounds for the ["Provider is invalid. Cannot change the Provider. Please detach your static site first if you wish to use to another deployment provider." issue](https://github.com/Azure/static-web-apps/issues/516). diff --git a/blog-website/blog/2021-08-19-bicep-syntax-highlighting-with-prismjs/index.md b/blog-website/blog/2021-08-19-bicep-syntax-highlighting-with-prismjs/index.md index b2890ce4cc2..6cfdb2c06fc 100644 --- a/blog-website/blog/2021-08-19-bicep-syntax-highlighting-with-prismjs/index.md +++ b/blog-website/blog/2021-08-19-bicep-syntax-highlighting-with-prismjs/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Bicep, PrismJS] image: ./bicep-syntax-highlighting-with-prismjs.webp hide_table_of_contents: false +description: 'Learn how to write attractive code snippets about Bicep using PrismJS and Docusaurus. This post shows you how to add syntax highlighting for Bicep.' --- Bicep is an amazing language, it's also very new. If you want to write attractive code snippets about Bicep, you can by using PrismJS (and Docusaurus). This post shows you how. diff --git a/blog-website/blog/2021-09-10-google-apis-authentication-with-typescript/index.md b/blog-website/blog/2021-09-10-google-apis-authentication-with-typescript/index.md index ac0a790676e..57db13c8e99 100644 --- a/blog-website/blog/2021-09-10-google-apis-authentication-with-typescript/index.md +++ b/blog-website/blog/2021-09-10-google-apis-authentication-with-typescript/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Google APIs, typescript] image: ./app-registration.png hide_table_of_contents: false +description: 'This guide shows how to use TypeScript to authenticate and access Google APIs with OAuth 2.0, specifically the Google Calendar API.' --- Google has a wealth of APIs which we can interact with. At the time of writing, there's more than two hundred available; including YouTube, Google Calendar and GMail (alongside many others). To integrate with these APIs, it's necessary to authenticate and then use that credential with the API. This post will take you through how to do just that using TypeScript. It will also demonstrate how to use one of those APIs: the Google Calendar API. @@ -158,7 +159,7 @@ export function makeOAuth2Client({ return new google.auth.OAuth2( /* YOUR_CLIENT_ID */ clientId, /* YOUR_CLIENT_SECRET */ clientSecret, - /* YOUR_REDIRECT_URL */ 'urn:ietf:wg:oauth:2.0:oob' + /* YOUR_REDIRECT_URL */ 'urn:ietf:wg:oauth:2.0:oob', ); } ``` diff --git a/blog-website/blog/2021-09-12-permissioning-azure-pipelines-bicep-role-assignments/index.md b/blog-website/blog/2021-09-12-permissioning-azure-pipelines-bicep-role-assignments/index.md index 6567c1f5a85..5a7c6ca972c 100644 --- a/blog-website/blog/2021-09-12-permissioning-azure-pipelines-bicep-role-assignments/index.md +++ b/blog-website/blog/2021-09-12-permissioning-azure-pipelines-bicep-role-assignments/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Role Assignments, Bicep, azure devops, Azure Pipelines] image: ./title-image.png hide_table_of_contents: false +description: 'Learn to permission Azure Pipelines to access resources through RBAC role assignments with Bicep. Includes examples and integration tests.' --- How can we deploy resources to Azure, and then run an integration test through them in the context of an Azure Pipeline? This post will show how to do this by permissioning our Azure Pipeline to access these resources using Azure RBAC role assignments. It will also demonstrate a dotnet test that runs in the context of the pipeline and makes use of those role assignments. diff --git a/blog-website/blog/2021-10-15-structured-data-seo-and-react/index.md b/blog-website/blog/2021-10-15-structured-data-seo-and-react/index.md index 85ccbbe7870..a028a7876b8 100644 --- a/blog-website/blog/2021-10-15-structured-data-seo-and-react/index.md +++ b/blog-website/blog/2021-10-15-structured-data-seo-and-react/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Structured Data, SEO, React] image: ./title-image.png hide_table_of_contents: false +description: 'Add structured data to your website to help search engines understand your content & get it in front of more people. Example shown in a React app.' --- People being able to discover your website when they search is important. This post is about how you can add structured data to a site. Adding structured data will help search engines like Google understand your content, and get it in front of more eyeballs. We'll illustrate this by making a simple React app which incorporates structured data. diff --git a/blog-website/blog/2021-10-18-docusaurus-meta-tags-and-google-discover/index.md b/blog-website/blog/2021-10-18-docusaurus-meta-tags-and-google-discover/index.md index 331c00b653e..0a775d468a4 100644 --- a/blog-website/blog/2021-10-18-docusaurus-meta-tags-and-google-discover/index.md +++ b/blog-website/blog/2021-10-18-docusaurus-meta-tags-and-google-discover/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Docusaurus] image: ./title-image.png hide_table_of_contents: false +description: 'Boost your websites appearance in Google Discover with high-quality images and `max-image-preview:large` meta tag setting in Docusaurus.' --- Google Discover is a way that people can find your content. To make your content more attractive, Google encourage using high quality images which are enabled by setting the `max-image-preview:large` meta tag. This post shows you how to achieve that with Docusaurus. diff --git a/blog-website/blog/2021-10-31-nswag-generated-c-sharp-client-property-name-clash/index.md b/blog-website/blog/2021-10-31-nswag-generated-c-sharp-client-property-name-clash/index.md index cab92d46273..d8e144d7258 100644 --- a/blog-website/blog/2021-10-31-nswag-generated-c-sharp-client-property-name-clash/index.md +++ b/blog-website/blog/2021-10-31-nswag-generated-c-sharp-client-property-name-clash/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [NSwag, C#] image: ./title-image.png hide_table_of_contents: false +description: 'Generate C# and TypeScript client libraries from OpenAPI / Swagger definitions using NSwag while overcoming language conflicts and numeric types.' --- NSwag is a great tool for generating client libraries in C# and TypeScript from Open API / Swagger definitions. You can face issues where Open API property names collide due to the nature of the C# language, and when you want to use `decimal` for your floating point numeric type over `double`. This post demonstrates how to get over both issues. diff --git a/blog-website/blog/2021-11-18-azure-standard-tests-with-bicep/index.md b/blog-website/blog/2021-11-18-azure-standard-tests-with-bicep/index.md index e53d1a89d06..db7889b9b0b 100644 --- a/blog-website/blog/2021-11-18-azure-standard-tests-with-bicep/index.md +++ b/blog-website/blog/2021-11-18-azure-standard-tests-with-bicep/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Azure, Bicep] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to deploy Azure standard tests using Bicep! This post goes through the process and includes a complete code snippet.' --- Azure standard tests are a tremendous way to monitor the uptime of your services in Azure. Sometimes also called availability tests, web tests and ping tests, this post goes through how to deploy one using Bicep. It also looks at some of the gotchas that you may encounter as you're setting it up. diff --git a/blog-website/blog/2021-11-22-typescript-vs-jsdoc-javascript/index.md b/blog-website/blog/2021-11-22-typescript-vs-jsdoc-javascript/index.md index d805991f2bf..ea36a356892 100644 --- a/blog-website/blog/2021-11-22-typescript-vs-jsdoc-javascript/index.md +++ b/blog-website/blog/2021-11-22-typescript-vs-jsdoc-javascript/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [javascript, typescript, JSDoc] image: ./title-image.png hide_table_of_contents: false +description: 'JSDoc annotations in JavaScript codebase add a new dynamic to the debate between JavaScript and TypeScript. It allows for type checking of JavaScript code.' --- There's a debate to be had about whether using JavaScript or TypeScript leads to better outcomes when building a project. The introduction of using JSDoc annotations to type a JavaScript codebase introduces a new dynamic to this discussion. This post will investigate what that looks like, and come to an (opinionated) conclusion. @@ -19,7 +20,7 @@ This blog evolved to become a talk: -Slightly surreally, there's an [audiobook version of this post](https://www.youtube.com/watch?v=pj8SoTZbCTE) thanks to ThePrimeagen. Essentially he reads the blog post and says he didn't like it. But it made me laugh 😉: +Slightly surreally, there's an [audiobook version of this post](https://www.youtube.com/watch?v=pj8SoTZbCTE) thanks to ThePrimeagen. Essentially he reads the blog post and says he didn't like it. But it made me laugh 😉: @@ -81,7 +82,7 @@ function stringsStringStrings( p1: string, p2?: string, p3?: string, - p4 = 'test' + p4 = 'test', ): string { // ... } diff --git a/blog-website/blog/2021-12-05-azure-static-web-app-deploy-previews-with-azure-devops/index.md b/blog-website/blog/2021-12-05-azure-static-web-app-deploy-previews-with-azure-devops/index.md index 12fd7bc4c2f..08384e7a2c7 100644 --- a/blog-website/blog/2021-12-05-azure-static-web-app-deploy-previews-with-azure-devops/index.md +++ b/blog-website/blog/2021-12-05-azure-static-web-app-deploy-previews-with-azure-devops/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Azure Static Web Apps, azure devops, Netlify deploy previews] image: ./title-image.png hide_table_of_contents: false +description: 'This post describes a pull request deployment preview mechanism for Azure Static Web Apps inspired by the Netlify offering.' --- I love [Netlify deploy previews](https://www.netlify.com/products/deploy-previews/). This post implements a pull request deployment preview mechanism for Azure Static Web Apps in the context of Azure DevOps which is very much inspired by the Netlify offering. @@ -122,7 +123,7 @@ variables: - name: appName value: 'our-static-web-app' - name: location - value: 'westeurope' # at time of writing static sites are available in limited locations such as westeurope + value: 'westeurope' # at time of writing static sites are available in limited locations such as westeurope - name: serviceConnection value: 'azureRMWestEurope' - name: azureResourceGroup # this resource group lives in westeurope @@ -288,7 +289,7 @@ async function run({ if (!pullRequestId) console.log( - 'No pull request id supplied, so will look up latest active PR' + 'No pull request id supplied, so will look up latest active PR', ); const pullRequestIdToUpdate = @@ -299,7 +300,7 @@ async function run({ } console.log( - `Updating ${systemCollectionUri}/${project}/_git/${repository}/pullrequest/${pullRequestIdToUpdate} with a preview URL of ${previewUrl}` + `Updating ${systemCollectionUri}/${project}/_git/${repository}/pullrequest/${pullRequestIdToUpdate} with a preview URL of ${previewUrl}`, ); const pullRequest = await getPullRequest({ @@ -314,12 +315,12 @@ async function run({ pullRequestId: pullRequestIdToUpdate, description: makePreviewDescriptionMarkdown( pullRequest.description!, - previewUrl + previewUrl, ), }); console.log( - `Updated pull request description a preview URL of ${previewUrl}` + `Updated pull request description a preview URL of ${previewUrl}`, ); } @@ -340,11 +341,11 @@ async function getGitApi({ const authHandler = pat ? nodeApi.getPersonalAccessTokenHandler( pat, - /** allowCrossOriginAuthentication */ true + /** allowCrossOriginAuthentication */ true, ) : nodeApi.getHandlerFromToken( sat, - /** allowCrossOriginAuthentication */ true + /** allowCrossOriginAuthentication */ true, ); const webApi = new nodeApi.WebApi(systemCollectionUri, authHandler); @@ -366,7 +367,7 @@ async function getActivePullRequestId({ config.project, undefined, /** skip */ 0, - /** top */ 1 + /** top */ 1, ); return topActivePullRequest.length > 0 @@ -391,7 +392,7 @@ async function getPullRequest({ /** skip */ 0, /** top */ 1, /** includeCommits */ false, - /** includeWorkItemRefs */ false + /** includeWorkItemRefs */ false, ); return pullRequest; } @@ -415,7 +416,7 @@ async function updatePullRequestDescription({ updatePullRequest, config.repository, pullRequestId, - config.project + config.project, ); } diff --git a/blog-website/blog/2021-12-12-open-graph-sharing-previews-guide/index.md b/blog-website/blog/2021-12-12-open-graph-sharing-previews-guide/index.md index da9d3d879e8..75c51ef26d4 100644 --- a/blog-website/blog/2021-12-12-open-graph-sharing-previews-guide/index.md +++ b/blog-website/blog/2021-12-12-open-graph-sharing-previews-guide/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Open Graph] image: ./title-image.png hide_table_of_contents: false +description: 'Create sharable social media previews with Open Graph tags. Learn the required tags, testing tools, and platform rendering issues in this guide.' --- The Open Graph protocol has become the standard mechanism for sharing rich content on the web. This post looks at what implementing Open Graph tags for sharable previews (often called social media previews) looks like, the tools you can use and also examines the different platform rendering issue. diff --git a/blog-website/blog/2021-12-19-azure-container-apps-bicep-and-github-actions/index.md b/blog-website/blog/2021-12-19-azure-container-apps-bicep-and-github-actions/index.md index b46ab683e4f..4ea9ea69487 100644 --- a/blog-website/blog/2021-12-19-azure-container-apps-bicep-and-github-actions/index.md +++ b/blog-website/blog/2021-12-19-azure-container-apps-bicep-and-github-actions/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [azure container apps, Bicep, GitHub Actions] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to deploy an Azure Container App to Azure with Bicep and GitHub Actions. A basic template is provided for deployment.' --- Azure Container Apps are an exciting way to deploy containers to Azure. This post shows how to deploy the infrastructure for an Azure Container App to Azure using Bicep and GitHub Actions. The [Azure Container App documentation](https://docs.microsoft.com/en-us/azure/container-apps/) features quickstarts for deploying your first container app using both the Azure Portal and the Azure CLI. These are great, but there's a gap if you prefer to deploy using Bicep and you'd like to get your CI/CD setup right from the beginning. This post aims to fill that gap. diff --git a/blog-website/blog/2021-12-27-azure-container-apps-build-and-deploy-with-bicep-and-github-actions/index.md b/blog-website/blog/2021-12-27-azure-container-apps-build-and-deploy-with-bicep-and-github-actions/index.md index ba006b65117..9ed363ea615 100644 --- a/blog-website/blog/2021-12-27-azure-container-apps-build-and-deploy-with-bicep-and-github-actions/index.md +++ b/blog-website/blog/2021-12-27-azure-container-apps-build-and-deploy-with-bicep-and-github-actions/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [azure container apps, Bicep, GitHub Actions, GitHub container registry] image: ./title-image.png hide_table_of_contents: false +description: 'Learn how to deploy a web app to Azure Container Apps using Bicep and GitHub Actions. This post covers the configuration and deployment of secrets.' --- This post shows how to build and deploy a simple web application to Azure Container Apps using Bicep and GitHub Actions. This includes the configuration and deployment of secrets. diff --git a/blog-website/blog/2021-12-28-azure-cli-show-query-output-properties/index.md b/blog-website/blog/2021-12-28-azure-cli-show-query-output-properties/index.md index 540eb95b762..d0fa0dc09d9 100644 --- a/blog-website/blog/2021-12-28-azure-cli-show-query-output-properties/index.md +++ b/blog-website/blog/2021-12-28-azure-cli-show-query-output-properties/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [azure cli, GitHub Actions] image: ./title-image.png hide_table_of_contents: false +description: 'Discover how to query Azure deployment outputs using the Azure CLI, bash, and jq, and convert them to GitHub Action job outputs.' --- It's often desirable to query the outputs of deployments to Azure. This post demonstrates how to do this using the Azure CLI, bash and jq. It also shows how to generically convert deployment outputs to GitHub Action job outputs. diff --git a/blog-website/blog/2021-12-29-preload-fonts-with-docusaurus/index.md b/blog-website/blog/2021-12-29-preload-fonts-with-docusaurus/index.md index 01bee11035b..66a3fec710c 100644 --- a/blog-website/blog/2021-12-29-preload-fonts-with-docusaurus/index.md +++ b/blog-website/blog/2021-12-29-preload-fonts-with-docusaurus/index.md @@ -5,6 +5,7 @@ authors: johnnyreilly tags: [Docusaurus, webpack] image: ./title-image.png hide_table_of_contents: false +description: 'Improve website performance by preloading web fonts in Docusaurus using `webpack-font-preload-plugin` or `headTags` API, as described in this tutorial.' --- When we're using custom fonts in our websites, it's good practice to preload the fonts to minimise the [flash of unstyled text](https://css-tricks.com/fout-foit-foft/). This post shows how to achieve this with Docusaurus. diff --git a/blog-website/blog/2023-03-18-migrating-from-ts-node-to-bun/index.md b/blog-website/blog/2023-03-18-migrating-from-ts-node-to-bun/index.md index 9382037e966..43a3e118643 100644 --- a/blog-website/blog/2023-03-18-migrating-from-ts-node-to-bun/index.md +++ b/blog-website/blog/2023-03-18-migrating-from-ts-node-to-bun/index.md @@ -149,7 +149,7 @@ The error message was suggesting I needed to explicitly state that I wanted to u { "compilerOptions": { - // "moduleResolution": "node", -+ "moduleResolution": "nodenext", ++ "moduleResolution": "Bundler", }, } ``` diff --git a/open-ai-description/bun.lockb b/open-ai-description/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..5696b905cda96457d16673ae460a8521f28835a0 GIT binary patch literal 41278 zcmeIb2{=_<^gn)ar8H5J424ok*Gy8O(4=UPCdtLcEv}1eYNRNYN;GPsxm5H<{d8Qo zJRJ@%P}L=XCk?{#@^PK-&h_H3+a z`{T(4u0baU8kIz?dslos9&Uo*C5#yDe~Uv!*Td(Feo#?&1|!tXM*!tB7)FrN8LkEX zUR)RW-Cj(1T>-y)LHa;YLl*DnxCD4Wnzujv4?;MkOGA1uh-Dz=O9=0if$I)%EyWb( zdvm=xEH@WME#!BF^c+a<0x{b^gy%Y+D`1H5_o3XLkX{Bc>URgqK;GvNBknB3nBQM? zJ)aXIVEZu`x21&lErhCfg8b_ccZ3)+S?-{#6)1yx?u8h6+Q9{uUkle5b9tT|Kd!)k z3tS_9HNUVwV7ScMg=x<#0Gdj0_oy00KxTKfs%h_fLiL zk=NDJCx{34`NB1pzZyu9HwgZR^&0>;;eCFth+;63;R4gWxje2n*Ixh;mA)U+u|7N> zHx7&K!u98P2V(g;U>qzrgze=8w=>vK4%*8CV&u_-80*^~V#H^Fov^%s0InMnFNbTy z`+|)y9O)*kek(L z)4l!Kl;ueOninL*&kJJX?F^2*P+uE}6@iBn$l(d#7IrY#2k%@BjgIy57qxRg1))B! zqU%d=4NVYA>_Yk{4>~XEJr`oMgAK%T5Dyn!4~7_dl|^x9QTp%tB>_KF@n^qO7G4`c z`IruuRQrNCC_5Afujd}Eubj2;gk#Log$3o^19n+5s0MbB;)D-W@k zu#xTTyUtRvII8yCw?tWU!+jnV8BdlUQ27vTcPuZctgx5SwxW%vCa-v-o4q84f3p3H z!13<>J!j2kmpho~zp~UiF5P3?YlqG;{faBEEavYhyqRCUCHcPMBDHGgm$qK!T^*M_ zj4(@18Zd9Ya!tft#}3~Xcz#_J$}~?Mqfqig+h%>hHKp{TNc zC|z6^zi#`s8;ZW(XF8fYRR`8t?mlYTutGjjvPfLLa{ptijSpW2m+alx=f_8bnRc3q z$JH*KCjCq4V8YwoHACba`mcUJD1u$Y>!~yR>zU8Sf#xv_%)U-yK9f2y%38c~w@LE% z=nZl+;g*Q^aXv)1-c9WhjA@yF-~t9N~DKVq>*O!ljPh+Rnk z^kIEm_2JUzyn)-22kMxJ4U5l9}9G8Wq9=9U9 zeNczx;eQmwZ_hYivy{OY1uU@kg~A-bfTfAiT3&(=0t|43{*H6u2-w;{%qs3Xyx?g5 z2e|E*K=3^Ps1JBp{uu2*Fm6pC_%VPVMk^nd)m8<9Uj}%45gz8xRtJJN1%<~0UQ&eo z-40C=68t*AWBpNYw0~Rm&j9>jz@y!;Y>ZnINcp7z7!G)}J%+a8H9_gIfG71Avb6kv zQhpfVM~L)q8TIoHg1-QGQ^2>@ZiIp0WdTUaNBi|9H?$BFye;5|K>3I@Yym^hCin=z zj~3xEAGRs23IzWU@K!W@tH5v*!K*;SnE)PfK-KC%@Y4W4QdItb!EXkK-KC%@ZNwohw^dUAilLWAo!zz$N2;GMrkYli>Q3WV)<_4r4a_~@P1$a{L*6KjYpFzW;4y_FY zzXR|%e~@z9+JEl>-h!roTg#V&hnrC%JeJ+o@*M!LOT)Ld{1t%5{_|h$p9Xkbzfo_( z(Hb3y{ojbn$No>oU|aBgVbfzQ(jVKfwK|aUX96DAU&NsfZNTd*x z9B4nZTWiav<3j*H81RV2{?pd|%Vof${)olUS{;b~vT&$@^Ur@Re;nYoMR>G9TlEhD zJgz^edt2Io=${Jsp@7G-b&#Z$f#B-_Pu6ej|D+$bL__c<@Zg8zw=KFOH^KV>9_NqN zmP_;^_(Omn3wYA*q#uy`nu-a&67bl6n!2y4bb>d7LtR{dNx5yEKf(cz?N9I|ZmL|8 zPRh>&ycOWleyuGVIS9Tx9KPuS9{Vlg+giRQ;K}?=+5q`m3Z(qSfM-GZ*neOtYIFIg z0B-?!Qg&x;; zV}XRH*}@@{;7tKf<}bvwwR}&&llo)XZ7u)EZ~CJRTN8->uK~ef;rA>KVr&1*H6@;t?j1+ zc-(&=_P_N1C4ip-_}|MFKsp?agn9+b57^aEe;??73B>*{;XXXSM*M%#zmLk#{S%JA z*0upDpAY!qP(IfEzu5mM;7tJ!aO&CXcROHuQvu6F!GJN@gW@%=L&$}DLO5ch=62K% zrduig0%Uw_Bf-|0kmef=AY=g+|On3YA6AhsQ>JNw8#(dD+#U5p`X!a^ev4c)( zpd;bMI+MU0Wn34s@L?5Msk#Q91NKPEi`BEpMv6bVemXuUo~#R^m3em}OyzLWgNRNkaj zviGLhYxb@mA|YAMpW4OZ!!h&g2cBgeRTqp5c6fXypE;z@>&?S1?{hh9p!*Pr2rtg9 zBrwx*=8st4DM^!)(7t{sdspp(2iM;miY)c_7L zoI6){>^E8QoUHdz8|ip!4<1H*2QN>n&-STubA{IhF*bU^-*n z#yj%T9Sw9(O_wz5Sh?Ni+yRjPfEU5ue#rB^6jvt=alL*4IenI>@;@+5E0(?gcM?CGPmpX*RJ{x zLrboHDGxP~leHQ=X`4s*8K;9QhVqj>wIuDM{Bm%V4Rxn;hV#<8s_QF#~R0<5m2 zpEDXhdgWspFYeh$U|PrWjk2vPin}#jySzMIF|PBMpaI)@?QrSxs=r6KHRAStlY*~h zonP|&aKE=#yOfTI4ip<}F-YgE);8IJPv6O=%>g2!FRrm9Fn4>-s9Nc1HPNN~LR5ZN z%f4Mkhs6q%cy=H4Gp)O7tz9^E>cUdPNn?L}Uj2Pk@9u|&>RB7SORQvkexsA%_sRTw zJ`fRJ+;5V=bktfc_ruO+m-CLRyrRc`m3tqhq;1@*^UziIBf~kmGS*spRN-xxVdwKQ z$Gm>$y*X;8_{H>&+mlYda!FDxPVevyhzKw42}xke>h;^Cw&zWejNbM=PNC+OiBER- z>}c`BC$Oa3f#>>b_H9yR?b!J7UA+QxMX{o?&Pl}%HTMn%KHGHq^^fZ}#wlI~BEk!= zjT!^f&DhNA>)Bg|SHG?vbyRZ1j$?A6p<73ckVzdek;C?RnR{WvL*+1s*t=aWyihsb zcX{7Y!>g0|0l7+>b#|)VI=E#GjhB8$&9sJ9(m+#c?iJ0orJ*8SK zW#~9B%l3WTC$G7^EKO!uI~j|Y>jz{+dfBDQ8gWdQrA}fUoEofffyRqxDW;lPDcaJ{tz#S$9Fm>< zE|;mk*!O^SW|^^P2i3CUcWl5kss}pP+6H&ruoV$1GO5Zc3xc4M>=uSu>X4SACjT5bj-ai5$km| zJ9%hoO;MOTt^Kx|-V@`zvRB?uvYT?!VdZScv$kn@PY0!0$6U(TdFAn%WHV*Ol{8*F zmm-1LH+qHsva-4F#}=NN6FFt(^6nkPw@be_dA9vF`+#&%!qLpY;||x_2WQ-<539(Z z$Vrvj6qZ)qrSJ5cQ>*5iNJu9E5z!aV>PTRoeNxiyO}m0go+`7{I-6Du8h&!YoZ8z@ z>)R?x(9ASg!r*qFF2u5ng#h3NiDE zi;Ldm`i415X^yuw=Y3$kxOhf&OhbY9wF6Q7J{<@6$dA-&!3xswE@^(YyWuHExIl#Hj(Ny>8F;;P+o!=}-PqcT3fmz=Gd zes@>$`3nm=S2rAf_VnPXB{dy%*E;vy?;U1q|59$&m?)EZKt%M#=T{P#7mn_-J{`Db z?BbrQj?9jk9sS*R@qzaPJEv}GFxr!uu$r&Xb)o_Pg#c zxshqrXP5Q4433RbFJ^j7-$8jdI-F$5->rJrX`uWGAR@eQ+|(GDQIe&;0a1MQ^NNf^ z%5SrhESIm`yrt%^4Xwo|kZE*?pIL0V!*1`-|zE?T{Qhc1Q8IDY}=t zOSzTYG`(A6qn-BE&~ICKMwjs^fkxY->uJ2?JOJsL$9LY{YkR}@;emlClEU`-j#Qst zc4E`GnL};z2Hl%`cz=p#h27SW_^Q}0mO+>8hP+t*?#x>k?@edwmpRSjxqMwlUx(n> zqcJe2kN@KOSb1A=-r&AY*BcUChrMeUzI9#IY~_#6)AV0{>|x&ZYQFN9^0Xkrnh!8*;?^dT6^&ojhba?3%c;^V;Q`1A5gz zV)~|!zhyMnIrvcCNK*mt^X_9Rl_Mfw?)BO9I`P;7_jTJBrf-S3clIWS#*615Brv~J zl~Ib zFsJgI!~n182FcA=j|}XVAvSf|v*=t#-3YUfF&2t(-h~IX3Ot=l_9*$R?l*Pspe^yX z>pvVn_)R((hzPGbA%&P3TYrta#N5T<^z7kL(x2`O4eYJD@V!Z*$Dy9QTYB$qZ|rrm zV?WKTnGce}cPPXdJh?W0nPl*d>00t<0#tAWLENC z8ZVA%5}0+RMyvg#>_2I8XRo}ayd}ung`c})*HiJEX7gtkk1A|`dvd?qCtp1+otjkI zeq#Bj^y_u)Z*?3PVOxCeEgkSS_nJ&v5PiJ$r}J(J zKm5(mYr*R885hFS=UlLTHQ+?b~cXoCw7)sRLcyD(o4NG z^2M2f7M~o)2*lG%bA4(04xsZEcn{;}I@`oQ(cY5CshYC>&3*0r>wEQGIjj3iC8Ia# zQ)XM89{q8?)VIUmx)r24?B67@i!tzf!W-L>JU^w3IWIoYcs1#~GC}&Pm6M*!t=L?9 zsqpa7L5vQMlOvM@%^yU&caU@1yI%iG$`HN%1~V7maF{gfh3(Dk#l|WHu6K@S7P*H# z9d-`aG-BU@bl!lQN5Y2{-qSYS6zJ#>e^~2W_)|i#(xsd^-Yw# zrZu)>`3>h|=>rRH4-Vqh=+`FCESc8fy(f)#5S^ECWR}b1x7AO(O*^@=qt5oXFIO-7 z6nx>FMD>@7V`rlKZy&ZOK0jutM3VO2HRJE~*G-8vz7S-WP?c(v%f zI_>=GcHWi0Wp|@+>Dra7Vrie^yqC^{c7E>V_g49KWJZSH{E=^XRb1!m6};{~T`d+xj_{mvvFz&Nuf{_ZUH5v?_to&tLStY??NmxM{%5m` zw}Zd)tsya{xe_B1-+4zelfHa%zG(iy_4JhuYU;l3;d|wFjGDA|`vI+gwkXW7&&jnr zp6RgZuo#}rl6Hf45siV#J6C^jQ+%JXZ!F?IyXijDG>8e|#Mi#|+vl@b;)jp3>-zym zd{-spNK*#c=J{BX4Fq!F{9$cUFo}W z1)Q$y7TI|O*Iqn+*ZuOQzACT%9MYJFHs#*GE&dUCeC}-HI=i43hO9D^yIt2|G+qNb?@Pv_oyUePe%r&rGV-00$-AQ2M zWgp(n&MvdxrL{0y)vast^}E`^Yqu6UJmYm@-F{(+W0&X)?=~9)^YP%&F*m}Ziyox) zTs1FX;0$g1qElb@WK?I|Su{qsVB>HJl{96>_NPYy8s?&~c=UmZ0IksEDh7W5L?wyeCIzPjN#yf=0 z`{;Jq1C4D44X?~P4LGw_`dC!wwKXHNCZ4@rsn{(pU3G~8|FPoHrR`T#+&jBui*A)> zsIFejYsrvpb$2)2QkFjWgvN_ykiaZRj*-<^VAinb@#Knwia}lb93E?~p<2J_?2No5 z8M)J6AD?WeTz5Ck)xB)hsN$gYyLTN68L{->VMb=@+p;pQF21uM_8m${A!hbpw{w84 z_%_Y*+lxAkW4)XF`an?Cr^TOMZwPpPY3qdr$Lyu&MQ3O(2|lMVG&I@uS-=|htd)@g zOiS_Wt7F66OCxE#@UE*dz#pNFUUlCuG4@ja?Vf|J&f3PtSaq&k%hynIRZH{UXPwhf zY=7|KyXd?pJ4W)fIet&qizh8l7@U5ZV}CKic?_$R#*2NK1g6Qu4O8}81yM&_{8e4n)69p`6EKPNDw^G;rJ zRPkNXg?({OQsaBssB-4*n5y2>qyC}o*~xabhj{7<3h4$qD}(l2Dt`KY|0b95bvj4a z$lPtKuKjx#4U0T-SKahgp@UMpc@=7YXV{mtBSkieDH|5@V z6d|*0WweKj?&=4HXG4pwyDu-7_)woks6oYXCl*r4c8D9#W2xM%2#$5-T*hNs>r*jIO( zGiBJ=(vdmCmY78;bsZ6<^CZe6ho7IAa*d^U`22kuuQi?b!H~h(m10{;dMJ;{9J=qr ztWL-3?$_z5wcC2+LiD;Z8K<&b+CSfVy+`FfllyO0=Q{dM&ia$xN+%3@uzpyUdx%0_u3J$pjdu*4w>-ftvSHoVGm@XPt=_)YWIA5?ux)=k4cDi4 zmmQxv=}w96b_>`2=Fhdl_p?H8W+%URwKl(l{=wm2QsOV2>u0RBg2p?R&b!pZXPC8p z$=khUz2y7Nd%D8-qi*}F2X_}})`g^+I;c5yP!1elSn2C!@4d8MUBYei#Ig~-@oyaN zE8JqY_mVr4OXD3!=gnHJBVo|9__1Wws*tKr%VzBIN>?wR*FX2Fpo84mu%RjC(&?R+ zPT6C&dbB~li@eEJX8&j0V-YJ4dD3i@KfJ|5ySdg7WvM`^q^ zbY8v5MFJy!NT7AmQPxK0h4)*fwP#-J-)Uxz-9(~$5Wr9n(f2Q$Hpz|&|nsMxymck}EDY3B7hf?mZN;ug+YzwaMe;yxa z*+KW3-u){Q?D&`)`Xk5oKec1Ar6RBN>0-}z3)B+qFL^%Aq3^3F(s_H9oMI+Q9$k{Q zYQLoa1kJ8F9dojJpPJA;Ge2xy{m_!Z!P4TE!TWk2{`M`So%*j#cp;bP zE`H&&HvL?~mdbmmI=;)wiubll33umwHu){8`XfA)^-Y2s7j7jG8 zNpxP#p-&bMUFW_$YQp3*TYHVZyT85Zbi<;rC;PlFf2W`@ZL3|Z=06QZ>oR9Ats2?+ z>+$Y$RIEpSn5!ORRVh6uy}%diPIxENdDoo^wCod5Vqvx<$x%jXnbqs{6DyO~OzF{k z-RE&b#xFMv=Uh z*Wf@JO&z~-9ihEvS2YWj2woYabzsh)tf3!>$=&fyk z_+g>p+t`#JT6d=|&P|3-OSUXK7+043a*a2`Ga^O!8=yKz5Wp!#wg{{ zc&E{M)1LY)?4W)wt5~7uynVM#<|>p+o2CyI-=#A1(6p+8T%F#%JNYJF*)C?^c~50V zHOD1?Th}|IFYf+q;H&mz!p1(h=Oy|&(0QkcUwgK|@cDu0>No0-3MP6#x_{7K{z|^n z{C96udo%5CoxeEN-Q4M8Swd<(qu&stdCw1Su|4+XvE!~c`?Af8#%0iWr_*_TE-zW6 zDq*!k;i$W9>~Gm2iF zx432y5-AmH9wz=~_5Hb}U9GpCj!TrO(V4X6fOi4?xn(9Hg_y|^H!7I$dHu-jJ@Vf* zV)DA){1g}AXl7%?n0CgpYR8u2KSov6dM0!@rTr{wfcn0Xz1SDu-%MFoWgF=(@!-Z| zbv!E~_MJuNbsFAdv0U0(gTaT_7_qvAGxNDg_}UHn6I)VzOA zeV8aOANb1mQ1Yx}RXIP{o>MsgC=57Ys-rh$iAqiF=V$G@Emr!Ne0HCq(Onv^Bb~Qo zrvKTL95?Umhe@~WRW*Xgy52tSc}=X^Q)5JSLi!LhFEIZ^?m8GRt;k4N1U3{k@n)A+Hy1X~@ z-lwzmlI@n$c<0i26Er?@y$-j(^lCWk)_GaQ;X$7UWekn`_`#%BX2vk3<=ORnP6gIj z8n$!3xQ;pVWle_?!;BTCrQ;%1PWW7{y@Y=<->9!Mop)64}C?r<$`iP3*BTi4AltklY z(|J27vt(TZeG~4~)Eq6(1GILMcacZ1Hu8P&jnyVK6UE_N9*0FXPJN&^| zmc`LwhVCbZ##lNPtG_?APwHUmyxuEpe0x1}`XQg?l(Z=S`y~20gnK{|n6vr5?>*eC z^^R?f>1O)b@`uCwwL|SjSmf)6Om~}Ekf}3KbJwxR4yLT>oQT-|g{d=F-$)pkWw5W@ zA-Bj*`swU^AR_v@5mJbm&LK0~_uj8Jlrv-4l;MjSID*nOS5oeNU`|i`e9H8E%IjXa zT`uoey+19uu*>PRkRtw%Ex|Rh%l8G&823=t_F9TEjh92`J)&ONpkO64Wg}x(L}YiR z1-B|cF+bk0btql-XH8>6c`?)Ml1kMBI}PK}i-g zUUxe05A8XQxzXbJ7v3e#2#S+ZkkKo?)NX9}KF5NB)jjt|zUuu|T~gO{NZ6p$8!rUU zw$UD{I@tc(;G&Rx&#>2HgHXqqv!Cj z`m6DEruKu@tW(FTjrWb$)TTC=#|_`FJG|P{_1*s$4%_(N#`BrwL#;0 zs=`~-;hj!f%1(IxJ)&r4X_oewg9H1k4^>Xu zq0nXVsl!rE6UVJvG(arJep}q5haFyP;rY(r@Ye!p0sP*K{M&Z$j|FPa^B3CXZ`%JI zcER=~|Ms7@j;j|})WZLNr(wC|-^wfRD*QM6uxI_Bl7{+`f1|Knx1aj`zm$eHApd^i z&z|u&jox=d;N_UK@Xr+*`|jT~27}lDpEWRGOwy=?Celb=OR-o>H~h{2Yk|KO_-lc` z7Wiv{zZUpwfxi~`Yk|KO_-lc`7Wiv{zZUpwfxi~`Yk|KO_-ldxV1ZE4%T_}#Ay|62 zzn`l%m*+14CrH}Fg_gFxABSV6s;{f+&t1UraUZN|sLJ-@dhmSQ;lLQfj|O4D-}pWs z&omA20s^_lvu5%)4ESyy?~wo@--Y9QbxgzaRY?#G_)Z+t@Hz?v1HRA3w00m$AQxcEh zzn{SGzVPo7@NWq4dw={kAHPw@y5aZf_$@hp_iX_(5@Zwz>WKPkfZ+EVvLM|-#(|6nK|4+W!EZkC8$~-1{H8?}qz}jWiTHFDE`6CJQ@)Cu$P zKGXy6!*nhP=Aq5;ezfCskZB0HhyCUl4T=>>n7bfvAEYMgs)M&5bJ>$gBXFJUIrj0AVWb+K`cSWgII%Dfs6ye{yPQ)`!imnU_SQY38EPL z@njIxX)4GR(QmvaeG>aJ+7bJu1&AAnD~JmS8^jr8E{GEd_Ekra*&rN{-+8f5;5d)~ z!8XLUlLW!G#CBzZV4e&P4hZd*31jKuv-OSV1em~NY}`0k>HRtxBVPvwBb4}eYA@!b zt8JnUrb8{DhlUalP>^G!t*;FR#x{UH8A^PWiHkYuX&Yh=S{iz4DDk=`F3#fw3m}m} z{2da%Y~tcxYyk%x=P}MgE{vd1;sK3f)6<5=x&t{fkVAZ>{VeA>pWaT1S4N7h>7GdGM!q;A9vuN=qD}P>;(M0($Yi1h zR89t1sS8+%c!LCtp)iMhw@3VGLJn#Tb1(7GN<2wI4)ki&n)q-fz9vOEuwq!iR;@df zL%dOnivfV@qQrkJ@pB0nnD}s&A)aZ82TjP)6|PytcP#O7Nnt46h}T)-9TRd4g!Li* zZi!z`Du+^me8EOMZ&Gaf+OQcTzHo`pPRJoEhR9nl@hS>AA{!9DzQq41OH4KPh;4Ho@l zO{sE-pJn0?meK&M0Bj;p%*10Xl>;?3_;V{zqyCTeq1cFjX5vQ{*r2ze)=guGZ)f6z zmePR25HHWf8!hBu%K;nl>rDL5LXN0k6VK1YLoKzUQ?pAGV;k6r_h{nf7BDz|z&hl+ zPU626%E7q`Hp)6O!kstqbPGA6ni8MV#P==ah{h@L5>33>LJrgh#{%&KP5jl0azHoY zNt$@P73IK~Bfh4IPh2WzC|V~0CO6#26EC<_4%K^!|7qeUSHuQmj(Dgho^(YyU<2aA zn)urNiD|l=rgNIE5BX-3_~wOjM6($2icP%tQaMz8n#TNLf1sy56lWLWJDd3U{aMbx zM=+TaiGOY42N-vdR0nDFz)d^_i*mqjO|vzfL;Q6UzrvKQ^>7IHgCh$#SqLQ_hQ-D3 z*%?C;2>=LyA1@885rF{J@D z=7@iA;>Q?rARSwQcn~L^jzwC-SRg*ei7(`z7~+MTcuN*x;DLttDJTAvMLAF(;>nzN zTo&cPDEaqO4)iywSN&ns8wppM$4?^>X|DHb%?A--_s9TGyw0hnK7P zrV0H0Ievj0zd8A;VN={~YTe)v4988liP255;4VKhL>e53r)co(5zcG$nmVqbcHb;E zm*vLsclG1)1zaDVO8}202;swF3jU8uwO}s@@Z;!k-8eh}R}dn)#GN~v>nRZM{Y`ar z{5T$5e}P|!HjnQ;&tKce&qGIeNTb6N{b1=C!&0TEE$~>-4CohfzzR!YQ9XwxbjOVh z!rNGWpr($ij~|BxU)Fn<;-H@IXAmDnr`}ldY+}Hv(+JMFP^9c@Nu|2@BluiDX@aJ~_*S(%26(8Lg->BESh2&(E8H^XCO+U<0ET^bs9-5u}?7bXPp`Y613}o&f(Xg&IgE z$l}KFVuv)=sF`~FdLvN&nm{qOq!&341T^`{q7DRGsL$`?jj9mLUO4ukU~He}d#Z@w z_o0n?{5INw4kyi4(NVLBXi6X|i7qK~v~tpJoOTHZPQgHcL%sESz&uUx@DsY1QHx_; zXqA7h282eqHc$p>Y1Rs7pe6%)BMPa7s}tXk6UgNR!8A-;t&Bx?;|UlG z4`3{)ai-%h@Zs~>E?%$-iGDQGWrasnpp5VbYY03!P$m_g=(xH0@K|hE%ltSl0bDOP zmgpsVGmO9A3f#XZK`GdUsG%j`xC&TaTo+ePFrUqHV+lCke0<~L!4-H0xUk&)e7sqF zw(ESDJH6+-asBwP9<%-Zxvo4=izQSF`#2;4ki+ue2m}E<9>Q>Ivx_(FE?}Zv!TgM?MDtx#KpkqK3e*p3+M_UdEu2Q1vG>oLL<~X% zu!tr>4p`O4T}0&WkIOcE2*DHh!~E=q{iNkGe!CM2`YnZJKsGE;I;{S4-8in$BmJn^ z$BhFWz!loGnOgjMBNXs!0yS5(v|j#NG;sWy037&4)_hx#BPT$UpI}LxfSbqB?Fv}> zC8c{y<^Ix0K=8{oFc`L|0WRPGq}K7)%=bZlY(75(5W*j=vapL6-0$KAt9{E0fN;>@ z{nY4zk$|Hftcd$DV?)+F|7N;_=&TOVqF z1pPV{0rJ-bm_OhpZwqA#PoDuR`~iAmvo+t%eok_L`*}fazo zM|2wudl-Yw*!-9Ke$oqZRQG7fihn2^c>a(|ZGWjD0lPP@Yon^oX!q-lK>KR~v|7tu z($5ueey&ts67B3bd=|X;htY;}1s^&ktao5RZ+I|iu7CdFZnW6HIjG5_CA*RHTB=q& zun0UqVt=P}Y{n*V0t^uNKiqB5;@xhX#>xVUcJ*_$Yo;vnh6kYJC)nH&-%a6|hSLPm zX+*Q*T6hm|2!FsvK(qz(@(Wh~Q6 zR{gh42Q@5OT9^K?l>w?hq(VcqJoWsxPXeajQm8K1(&XdDY20`L1MP}Jw^XBFH-~5! zSnOGBvRee}idI@T=*l|SIqB|e~7n>k5_Zk zAMGwEfObV$q9p|z3lm|ff+=K66D1%;7;Na4%K4>+fcxbdZ3+K1zuY!9C!iaDQ<}Ea zLGf@AKp4R!XDIB@@OH<|$8~$=h4&8B-E3+i5-u*n4J5}m03LM7(+f+$_2zI~ z-Tc`sf361$PomfYI0tWLbp7FODC!TX!oJv2y+r%kKd1$)O=q^MqYJ-;LG1!@Cju*N z%a1P9J1~GyF)Sr;RzS^3?r=ow69juKczTBEr@3+c`>nwCdlHTte5h@{&3`|N0HR-~ zY09{wyKwPnrrBtB0S&d%=;Qv{xFsEg?-m-5M*!UTn`#7I;i*5xLqAKw{htpHw}L?& z7lF@w4zC&Q=(j-$^h;RDL{A=GK5lG(PxuQ2SFZqgAwn+wU3`4JIBZ_yHLMsMcumlF z%?t2$p#Q!mO}7@0rkcxugQ;qHGAO;C~=$-;pO z3W|mqJok!@Nt@~V^fT6G4yJWsKSbD2K?_{U1spGqHwWHD>cDeAb7lPNW>6U)9okS| z>d0Go2n=A_6_DVUIiM2`b@JY}8Et;PZUv&B7u4BgOM|}goh?8cf5YMeU*4kz!gs;{ I=l%cx1EYW(8vp fs.statSync(path.join(rootBlogPath, file)).isDirectory()) + .map((file) => path.join(rootBlogPath, file)); + + blogDirs.sort().reverse(); + + return blogDirs; +} + +interface BlogPost { + path: string; + content: string; +} + +interface BlogPostWithDescription extends BlogPost { + description: string; +} + +async function generatePostsWithDescription() { + const blogDirs = await getBlogDirsOrderedDescending(); + + const postsWithoutDescription: BlogPost[] = []; + + for (const blogDir of blogDirs) { + console.log(`Processing ${blogDir}`); + + const indexMdPath = path.join(blogDir, 'index.md'); + const blogPostContent = await fs.promises.readFile(indexMdPath, 'utf-8'); + + const frontMatter = blogPostContent.split('---')[1]; + const hasDescription = frontMatter.includes('\ndescription: '); + if (!hasDescription) { + postsWithoutDescription.push({ + path: indexMdPath, + content: blogPostContent, + }); + } + } + + console.log( + `Found ${postsWithoutDescription.length} posts without description`, + ); + + const postsWithDescription: BlogPostWithDescription[] = []; + + for (const post of postsWithoutDescription) { + const [, frontmatter, article] = post.content.split('---'); + + console.log( + `** Generating description for ${post.path + .replace('/index.md', '') + .split('/') + .pop()}`, + ); + const description = await produceSummary(article); + + if (description) { + postsWithDescription.push({ ...post, description }); + console.log(`** description: ${description}`); + + await fs.promises.writeFile( + post.path, + `---${frontmatter}description: '${description.replaceAll("'", '')}' +---${article}`, + ); + } else { + console.log(`** no description generated`); + } + + // break; + } + + return postsWithDescription; +} + +async function main() { + const startedAt = new Date(); + + const postsWithDescription: BlogPostWithDescription[] = + await generatePostsWithDescription(); + + const finishedAt = new Date(); + const duration = (finishedAt.getTime() - startedAt.getTime()) / 1000; + console.log( + `${postsWithDescription.length} summaries generated in ${duration} seconds`, + ); +} + +await main(); diff --git a/open-ai-description/package.json b/open-ai-description/package.json new file mode 100644 index 00000000000..7d0655eb87b --- /dev/null +++ b/open-ai-description/package.json @@ -0,0 +1,18 @@ +{ + "name": "open-ai-description", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@azure/openai": "next", + "dotenv": "latest", + "@azure/identity": "^1.4.0" + }, + "devDependencies": { + "bun-types": "^0.8.1", + "typescript": "^5.2.0" + }, + "scripts": { + "start": "bun index.ts" + } +} diff --git a/open-ai-description/sample.env b/open-ai-description/sample.env new file mode 100644 index 00000000000..c1189593b24 --- /dev/null +++ b/open-ai-description/sample.env @@ -0,0 +1,3 @@ +# Used to connect with the Azure OpenAI. Retrieve these +# values from an Azure OpenAI instance in the Azure Portal. +ENDPOINT="https://.openai.azure.com" diff --git a/open-ai-description/summarizer.ts b/open-ai-description/summarizer.ts new file mode 100644 index 00000000000..3a767542e9e --- /dev/null +++ b/open-ai-description/summarizer.ts @@ -0,0 +1,109 @@ +import { OpenAIClient } from '@azure/openai'; +import { AzureCliCredential } from '@azure/identity'; + +// Make sure you have az login'd and have the correct subscription selected +// debug with: +// bun --inspect-brk open-ai-description/index.ts +// or: +// cd open-ai-description +// bun --inspect-brk index.ts + +interface OpenAiClientAndDeploymentName { + openAIClient: OpenAIClient; + deploymentName: string; +} + +let openAiClientAndDeploymentName: OpenAiClientAndDeploymentName | undefined; + +function getClientAndDeploymentName(): OpenAiClientAndDeploymentName { + if (openAiClientAndDeploymentName) { + return openAiClientAndDeploymentName; + } + + // You will need to set these environment variables or edit the following values + const endpoint = + process.env['ENDPOINT'] || 'https://.openai.azure.com'; + + // This will use the Azure CLI's currently logged in user; + // make sure you've done `az login` and have the correct subscription selected + const credential = new AzureCliCredential(); + const openAIClient = new OpenAIClient( + endpoint, + credential /* new AzureKeyCredential(azureApiKey) */, + ); + const deploymentName = 'OpenAi-gpt-35-turbo'; + + openAiClientAndDeploymentName = { openAIClient, deploymentName }; + + return openAiClientAndDeploymentName; +} + +export async function produceSummary(article: string): Promise { + const { openAIClient, deploymentName } = getClientAndDeploymentName(); + const minChars = 120; + const maxChars = 156; + + const messages = [ + { + role: 'system', + content: `You are a summarizer. You will be given the text of an article and will produce a summary / meta description which summarizes the article. The summary / meta descriptions you produce must be between ${minChars} and ${maxChars} characters long. If they are longer or shorter than that they cannot be used. Avoid using the \`'\` character as it is not supported by the blog website - you may use the \`’\` character instead. Do not use the expression "the author" or "the writer" in your summary.`, + }, + { + role: 'user', + content: `Here is an article to summarize: + +${article}`, + }, + ]; + + let attempts = 0; + const maxAttempts = 10; + let summary = ''; + while (attempts++ < maxAttempts) { + console.log(`Attempt ${attempts} of ${maxAttempts}`); + + // This will use the Azure CLI's currently logged in user; + // make sure you've done `az login` and have the correct subscription selected + const result = await openAIClient.getChatCompletions( + deploymentName, + messages, + { + temperature: 0.9, + }, + ); + + for (const choice of result.choices) { + summary = choice.message?.content || ''; + + if (summary.length >= minChars && summary.length <= maxChars) { + return summary; + } + console.log(`Summary was ${summary.length} characters long; no good`); + } + + messages.push( + { + role: 'assistant', + content: summary, + }, + { + role: 'user', + content: + summary.length < minChars + ? `Too short; try again please - we require a summary that is between ${minChars} and ${maxChars} characters long.` + : `Too long; try again please - we require a summary that is between ${minChars} and ${maxChars} characters long.`, + }, + ); + + console.log(messages); + + await sleep(500); + } + + console.log(`Failed to produce a summary in ${maxAttempts} attempts`); + return ''; +} + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/open-ai-description/tsconfig.json b/open-ai-description/tsconfig.json new file mode 100644 index 00000000000..68d46c7ce39 --- /dev/null +++ b/open-ai-description/tsconfig.json @@ -0,0 +1,107 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "esnext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": [ + "ESNext" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "esnext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "bun-types" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "error" /* Specify emit/checking behavior for imports that are only used for types. */, + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/trim-xml/bun.lockb b/trim-xml/bun.lockb index 97481bf55fd8404bc8b757285f0fdcdbe41984c9..95fc704d10858474e1192cad809cd3a53a709312 100755 GIT binary patch delta 380 zcmbOx`%htlo>JnA&yUzx^5kFn|5-3KxpY}VW9KD~-)z-?4&2qya=D%Pj(=i+*yIb$ zEPM<=&;TNUAc<>Y#RjttjQmH=u`)2IKm-|Jd?_fu!1^>dBa{uIPJz{Lj$;&KVr2*N znI{LbXit8?&a!z0^HJuANvFB_XEy7#ZJ4pmwUH%owd_`@k?-8UkZxQn-b$z<@ob3F}Yh2~1Ijea0D5P)33GMSOXdJ;#) z~#Dv%x zAfN$CS8z{|DxS>Mme2DtZag1V2tUzT9?2`jov?o7c zXW6`h`6zS5``fdo%JnNw6V73Ju+b+nEdE z>~0njOz!%4Xuq1|0SjZT)E`dycT4AkY=yc&1nPnUAfIJ2BZu`QjtZ^=91zhf9Fudn z9Ap?6{{4plkT55lU|>+;oP3PSjVk~w#=ua)Ia!R`i)#gxyM}9W7PmFCsh;`d72I#Q mesDodwcwsSkEe+%1M2yIyqmRnw=%H