├── .gitignore ├── CODE_OF_CONDUCT.md ├── Chapter01 ├── Code │ ├── constrained-generics.ts │ ├── decorators │ │ ├── class-decorators.ts │ │ └── function-decorators.ts │ ├── generics.ts │ ├── index.html │ ├── intersection-types.ts │ ├── maps.ts │ ├── mixins.ts │ ├── promises.ts │ ├── rest-spread.ts │ ├── type-aliases.ts │ ├── type-assertion.ts │ └── union-types.ts └── tsconfig.json ├── Chapter02 ├── code │ └── MarkdownParser.ts ├── index.html └── tsconfig.json ├── Chapter03 ├── .gitignore ├── .vscode │ └── launch.json ├── README.md ├── images.d.ts ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── Database │ │ ├── Database.ts │ │ └── TableBuilder.ts │ ├── FormValidation.tsx │ ├── PersonalDetails.tsx │ ├── PersonalDetailsTableBuilder.tsx │ ├── RecordState.ts │ ├── State.ts │ ├── Types.ts │ ├── Validation │ │ ├── AddressValidation.ts │ │ ├── IValidation.ts │ │ ├── PersonValidation.ts │ │ └── PhoneValidation.ts │ ├── Validators │ │ ├── IValidator.ts │ │ ├── MinLengthValidator.ts │ │ └── RegularExpressionValidator.ts │ ├── index.tsx │ └── registerServiceWorker.ts ├── tsconfig.json ├── tsconfig.prod.json ├── tsconfig.test.json └── tslint.json ├── Chapter04 ├── .vscode │ └── tasks.json ├── Client │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── angular.json │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.e2e.json │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── components │ │ │ │ ├── fileupload │ │ │ │ │ ├── fileupload.component.html │ │ │ │ │ ├── fileupload.component.scss │ │ │ │ │ ├── fileupload.component.spec.ts │ │ │ │ │ └── fileupload.component.ts │ │ │ │ └── page-body │ │ │ │ │ ├── page-body.component.html │ │ │ │ │ ├── page-body.component.scss │ │ │ │ │ ├── page-body.component.spec.ts │ │ │ │ │ └── page-body.component.ts │ │ │ ├── services │ │ │ │ ├── ContextServiceBase.ts │ │ │ │ ├── add-image.service.spec.ts │ │ │ │ ├── add-image.service.ts │ │ │ │ ├── file-preview-service.service.spec.ts │ │ │ │ ├── file-preview-service.service.ts │ │ │ │ ├── load-image.service.spec.ts │ │ │ │ ├── load-image.service.ts │ │ │ │ ├── transfer-data.service.spec.ts │ │ │ │ └── transfer-data.service.ts │ │ │ └── types.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── browserslist │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── karma.conf.js │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── tslint.json │ ├── tsconfig.json │ └── tslint.json └── Server │ ├── .gitignore │ ├── AdvancedTypeScriptProjectsChapter4.ts │ ├── Database.ts │ ├── README │ ├── Routing │ ├── AddRouter.ts │ ├── FindByIdRouter.ts │ ├── GetPicturesRouter.ts │ ├── Router.ts │ ├── Routes.ts │ └── RoutingEngine.ts │ ├── dist │ ├── AddRouter.js │ ├── AdvancedTypeScriptProjectsChapter4.js │ ├── Database.js │ ├── Router.js │ ├── Routing │ │ ├── AddRouter.js │ │ ├── FindByIdRouter.js │ │ ├── GetPicturesRouter.js │ │ ├── Router.js │ │ ├── Routes.js │ │ └── RoutingEngine.js │ └── server.js │ ├── package-lock.json │ ├── package.json │ ├── server.ts │ └── tsconfig.json ├── Chapter05 ├── .idea │ ├── Chapter05.iml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── misc.xml │ ├── modules.xml │ ├── vcs.xml │ └── workspace.xml ├── Client │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── angular.json │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.e2e.json │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── components │ │ │ │ ├── add-task │ │ │ │ │ ├── add-task.component.html │ │ │ │ │ ├── add-task.component.scss │ │ │ │ │ ├── add-task.component.spec.ts │ │ │ │ │ └── add-task.component.ts │ │ │ │ ├── alltasks │ │ │ │ │ ├── alltasks.component.html │ │ │ │ │ ├── alltasks.component.scss │ │ │ │ │ ├── alltasks.component.spec.ts │ │ │ │ │ └── alltasks.component.ts │ │ │ │ ├── overduetasks │ │ │ │ │ ├── overduetasks.component.html │ │ │ │ │ ├── overduetasks.component.scss │ │ │ │ │ ├── overduetasks.component.spec.ts │ │ │ │ │ └── overduetasks.component.ts │ │ │ │ └── todo-card │ │ │ │ │ ├── todo-card.component.html │ │ │ │ │ ├── todo-card.component.scss │ │ │ │ │ ├── todo-card.component.spec.ts │ │ │ │ │ └── todo-card.component.ts │ │ │ └── types │ │ │ │ ├── SubscriptionBase.ts │ │ │ │ ├── TodoItemInput.ts │ │ │ │ └── TodoItemQuery.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── browserslist │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── karma.conf.js │ │ ├── main.ts │ │ ├── models │ │ │ ├── ITodoItemInput.js │ │ │ └── TodoItem.js │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── tslint.json │ ├── tsconfig.json │ └── tslint.json ├── Common │ └── models │ │ ├── ITodoItemInput.ts │ │ └── TodoItem.ts └── Server │ ├── .gitignore │ ├── apolloserver.ts │ ├── database │ ├── DataAccessBase.ts │ ├── Database.ts │ ├── Schema.ts │ └── TodoDataAccess.ts │ ├── graph │ ├── Prefill.ts │ ├── TodoItem.ts │ ├── TodoItemInput.ts │ └── TodoItemResolver.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── Chapter06 ├── .idea │ ├── Chapter06.iml │ ├── codeStyles │ │ └── codeStyleConfig.xml │ ├── compiler.xml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── misc.xml │ ├── modules.xml │ ├── vcs.xml │ └── workspace.xml ├── Client │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── angular.json │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.e2e.json │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── Types │ │ │ │ ├── Logging.ts │ │ │ │ └── user.logon.ts │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── components │ │ │ │ ├── generalchat │ │ │ │ │ ├── generalchat.component.html │ │ │ │ │ ├── generalchat.component.scss │ │ │ │ │ ├── generalchat.component.spec.ts │ │ │ │ │ └── generalchat.component.ts │ │ │ │ ├── navigation │ │ │ │ │ ├── navigation.component.html │ │ │ │ │ ├── navigation.component.scss │ │ │ │ │ ├── navigation.component.spec.ts │ │ │ │ │ └── navigation.component.ts │ │ │ │ └── secretchat │ │ │ │ │ ├── secretchat.component.html │ │ │ │ │ ├── secretchat.component.scss │ │ │ │ │ ├── secretchat.component.spec.ts │ │ │ │ │ └── secretchat.component.ts │ │ │ └── services │ │ │ │ ├── authorization.service.spec.ts │ │ │ │ ├── authorization.service.ts │ │ │ │ ├── authorization.ts │ │ │ │ ├── chat-messages.service.spec.ts │ │ │ │ ├── chat-messages.service.ts │ │ │ │ ├── oauth-authorization.service.spec.ts │ │ │ │ └── oauth-authorization.service.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── browserslist │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── karma.conf.js │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── tslint.json │ ├── tsconfig.json │ └── tslint.json └── Server │ ├── .gitignore │ ├── Database │ ├── DataAccess │ │ ├── DataAccessBase.ts │ │ └── Messages.ts │ ├── Database.ts │ └── Types.ts │ ├── package-lock.json │ ├── package.json │ ├── server.ts │ └── tsconfig.json ├── Chapter07 ├── .gitignore ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── map-view │ │ │ │ ├── map-view.component.html │ │ │ │ ├── map-view.component.scss │ │ │ │ ├── map-view.component.spec.ts │ │ │ │ └── map-view.component.ts │ │ │ └── mappingcontainer │ │ │ │ ├── mappingcontainer.component.html │ │ │ │ ├── mappingcontainer.component.scss │ │ │ │ ├── mappingcontainer.component.spec.ts │ │ │ │ └── mappingcontainer.component.ts │ │ ├── general │ │ │ ├── MapEvents.ts │ │ │ ├── MapGeocode.ts │ │ │ ├── PinModel.ts │ │ │ └── PinsModel.ts │ │ └── services │ │ │ ├── firebase-map-pins.service.spec.ts │ │ │ ├── firebase-map-pins.service.ts │ │ │ ├── points-of-interest.service.spec.ts │ │ │ └── points-of-interest.service.ts │ ├── assets │ │ └── .gitkeep │ ├── browserslist │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ └── tsconfig.app.json └── tsconfig.json ├── Chapter08 ├── Services │ ├── .dockerignore │ ├── Addresses │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── Routing │ │ │ ├── GetAddressRouting.ts │ │ │ └── SaveAddressRouting.ts │ │ ├── api │ │ │ └── Models │ │ │ │ ├── Addresses.ts │ │ │ │ └── AddressesService.ts │ │ ├── build.cmd │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── service.ts │ │ └── tsconfig.json │ ├── Common │ │ ├── .gitignore │ │ ├── Model │ │ │ ├── DatabaseModelBase.ts │ │ │ └── FirestoreService.ts │ │ ├── Routing │ │ │ ├── Router.ts │ │ │ └── RoutingEngine.ts │ │ ├── Server.ts │ │ ├── package-lock.json │ │ └── package.json │ ├── Leads │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── Routing │ │ │ ├── GetLeadsRouting.ts │ │ │ └── SaveLeadsRouting.ts │ │ ├── api │ │ │ └── Models │ │ │ │ ├── Lead.ts │ │ │ │ └── LeadService.ts │ │ ├── build.cmd │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── service.ts │ │ └── tsconfig.json │ ├── People │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── Routing │ │ │ ├── GetPeopleRouting.ts │ │ │ └── SavePeopleRouting.ts │ │ ├── api │ │ │ └── Models │ │ │ │ ├── People.ts │ │ │ │ └── PersonService.ts │ │ ├── build.cmd │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── server.ts │ │ └── tsconfig.json │ ├── docker-compose.yml │ ├── runall.cmd │ └── tsconfig.json ├── SwaggerAPI │ └── typescript-node-client-generated │ │ ├── .gitignore │ │ ├── .swagger-codegen-ignore │ │ ├── .swagger-codegen │ │ └── VERSION │ │ ├── api.ts │ │ └── git_push.sh └── crmclient │ ├── .gitignore │ ├── README.md │ ├── images.d.ts │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── components │ │ ├── AddAddress.tsx │ │ ├── AddLead.tsx │ │ ├── StatusChoice.tsx │ │ ├── addperson.tsx │ │ ├── addresses-choice.tsx │ │ ├── addresses.tsx │ │ ├── leads.tsx │ │ ├── people-choice.tsx │ │ └── people.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ └── registerServiceWorker.ts │ ├── tsconfig.json │ ├── tsconfig.prod.json │ ├── tsconfig.test.json │ └── tslint.json ├── Chapter09 ├── .browserslistrc ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── Models │ │ ├── DrawPose.ts │ │ ├── ImageClassifier.ts │ │ ├── PoseClassifier.ts │ │ └── TensorInformation.ts │ ├── assets │ │ └── logo.png │ ├── components │ │ └── HelloWorld.vue │ ├── main.ts │ ├── router.ts │ ├── shims-tsx.d.ts │ ├── shims-vue.d.ts │ ├── store.ts │ └── views │ │ ├── Home.vue │ │ └── Pose.vue ├── tsconfig.json └── tslint.json ├── Chapter10 ├── .gitignore ├── .vs │ ├── AdvancedTypeScript3Discogs │ │ └── config │ │ │ └── applicationhost.config │ └── Chapter10 │ │ ├── DesignTimeBuild │ │ └── .dtbcache │ │ ├── config │ │ └── applicationhost.config │ │ └── v16 │ │ └── Server │ │ └── sqlite3 │ │ ├── db.lock │ │ └── storage.ide ├── AdvancedTypeScript3Discogs.sln ├── AdvancedTypeScript3Discogs.sln.DotSettings └── AdvancedTypeScript3Discogs │ ├── AdvancedTypeScript3Discogs.csproj │ ├── Controllers │ └── HomeController.cs │ ├── Models │ ├── Discogs │ │ ├── CommunityInfo.cs │ │ ├── DiscogsClient.cs │ │ ├── EntityType.cs │ │ ├── IDiscogsClient.cs │ │ ├── PaginationResults.cs │ │ ├── Results.cs │ │ ├── SearchResult.cs │ │ └── Urls.cs │ └── ErrorViewModel.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Startup.cs │ ├── TypeScript │ └── discogHelper.ts │ ├── Views │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ ├── Index.cshtml │ │ └── Privacy.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _CookieConsentPartial.cshtml │ │ ├── _Layout.cshtml │ │ └── _ValidationScriptsPartial.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── tsconfig.json │ └── wwwroot │ ├── css │ ├── site.css │ └── site.min.css │ ├── favicon.ico │ ├── images │ ├── banner1.svg │ ├── banner2.svg │ └── banner3.svg │ ├── js │ ├── discogHelper.js │ ├── discogHelper.js.map │ ├── site.js │ └── site.min.js │ └── lib │ ├── bootstrap │ ├── .bower.json │ └── LICENSE │ ├── jquery-validation-unobtrusive │ ├── .bower.json │ ├── LICENSE.txt │ ├── jquery.validate.unobtrusive.js │ └── jquery.validate.unobtrusive.min.js │ ├── jquery-validation │ ├── .bower.json │ └── LICENSE.md │ └── jquery │ ├── .bower.json │ └── LICENSE.txt ├── LICENSE ├── README.md ├── node_modules ├── @types │ └── bingmaps │ │ ├── Autosuggest.d.ts │ │ ├── Clustering.d.ts │ │ ├── Contour.d.ts │ │ ├── DataBinning.d.ts │ │ ├── Directions.d.ts │ │ ├── DrawingTools.d.ts │ │ ├── GeoJson.d.ts │ │ ├── HeatMapLayer.d.ts │ │ ├── LICENSE │ │ ├── README.md │ │ ├── Search.d.ts │ │ ├── SpatialDataService.d.ts │ │ ├── SpatialMath.d.ts │ │ ├── Traffic.d.ts │ │ ├── WellKnownText.d.ts │ │ ├── index.d.ts │ │ └── package.json └── bingmaps │ ├── .npmignore │ ├── LICENSE.md │ ├── README.md │ ├── index.js │ ├── package.json │ └── types │ └── MicrosoftMaps │ ├── ConfigurationDrivenMaps.d.ts │ ├── CustomMapStyles.d.ts │ ├── Microsoft.Maps.All.d.ts │ ├── Microsoft.Maps.d.ts │ └── Modules │ ├── Autosuggest.d.ts │ ├── Clustering.d.ts │ ├── Contour.d.ts │ ├── DataBinning.d.ts │ ├── Directions.d.ts │ ├── DrawingTools.d.ts │ ├── GeoJSON.d.ts │ ├── GeoXml.d.ts │ ├── HeatMapLayer.d.ts │ ├── Search.d.ts │ ├── SpatialDataService.d.ts │ ├── SpatialMath.d.ts │ ├── Traffic.d.ts │ └── WellKnownText.d.ts ├── package-lock.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | /Chapter10/.vs 4 | -------------------------------------------------------------------------------- /Chapter01/Code/decorators/class-decorators.ts: -------------------------------------------------------------------------------- 1 | let classUser = {user: "peter", roles : [{role:"user"}, {role:"admi1n"}] }; 2 | 3 | function IsInRoleClass(role : string) : boolean { 4 | return classUser.roles.some(r => r.role === role); 5 | } 6 | 7 | function RoleClass(role : string) { 8 | return function(constructor : Function) { 9 | if (!IsInRoleClass(role)) { 10 | throw new Error(`The user is not authorised to access this class`); 11 | } 12 | } 13 | } 14 | @RoleClass("admin") 15 | class RestrictedClass { 16 | constructor() { 17 | console.log(`Inside the constructor`); 18 | } 19 | Validate() { 20 | console.log(`Validating`); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter01/Code/intersection-types.ts: -------------------------------------------------------------------------------- 1 | export class Grid { 2 | Width : number = 0; 3 | Height : number = 0; 4 | Padding : number; 5 | constructor(padding:number) { 6 | this.Padding = padding; 7 | } 8 | } 9 | 10 | export class Margin { 11 | Left : number = 0; 12 | Top : number = 0; 13 | Width : number = 10; 14 | Height : number = 20; 15 | Padding?: number; 16 | } 17 | 18 | function ConsolidatedGrid(grid : Grid, margin : Margin) : Grid & Margin { 19 | let consolidatedGrid = {...margin}; 20 | 21 | consolidatedGrid.Left = margin.Left; 22 | consolidatedGrid.Top = margin.Top; 23 | consolidatedGrid.Width = margin.Width + grid.Width; 24 | consolidatedGrid.Height = margin.Height + grid.Height; 25 | consolidatedGrid.Padding = margin.Padding ? margin.Padding : grid.Padding; 26 | 27 | return consolidatedGrid; 28 | } 29 | 30 | let grid :Grid = {Height:20, Width:10, Padding:5}; 31 | let x = ConsolidatedGrid(grid, {Left:5,Top:5,Width:5,Height:5}); 32 | 33 | console.log(`Left : ${x.Left}, Top : ${x.Top}, Width : ${x.Width}, Height : ${x.Height}, Padding : ${x.Padding}`) -------------------------------------------------------------------------------- /Chapter01/Code/maps.ts: -------------------------------------------------------------------------------- 1 | enum Genre { 2 | Rock, 3 | CountryAndWestern, 4 | Classical, 5 | Pop, 6 | HeavyMetal 7 | } 8 | 9 | class MusicCollection { 10 | private readonly collection : Map; 11 | constructor() { 12 | this.collection = new Map(); 13 | } 14 | 15 | public Add(genre : Genre, artist : string[]) : void { 16 | this.collection.set(genre, artist); 17 | } 18 | 19 | public Get(genre : Genre) : string[] | undefined { 20 | return this.collection.get(genre); 21 | } 22 | } 23 | 24 | let collection = new MusicCollection(); 25 | collection.Add(Genre.Classical, [`Debussy`, `Bach`, `Elgar`, `Beethoven`]); 26 | collection.Add(Genre.CountryAndWestern, [`Dolly Parton`, `Toby Keith`, `Willie Nelson`]); 27 | collection.Add(Genre.HeavyMetal, [`Tygers of Pan Tang`, `Saxon`, `Doro`]); 28 | collection.Add(Genre.Pop, [`Michael Jackson`, `Abba`, `The Spice Girls`]); 29 | collection.Add(Genre.Rock, [`Deep Purple`, `Led Zeppelin`, `The Dixie Dregs`]); 30 | 31 | console.log(collection.Get(Genre.HeavyMetal)); 32 | -------------------------------------------------------------------------------- /Chapter01/Code/mixins.ts: -------------------------------------------------------------------------------- 1 | type Constructor = new(...args: any[]) => T; 2 | 3 | function RecordStatus(base : T) { 4 | return class extends base { 5 | private deleted : boolean = false; 6 | 7 | get Deleted() : boolean { 8 | return this.deleted; 9 | } 10 | Delete() : void { 11 | this.deleted = true; 12 | console.log(`The record has been marked as deleted.`); 13 | } 14 | } 15 | } 16 | 17 | function Timestamp(base : T) { 18 | return class extends base { 19 | Updated : Date = new Date(); 20 | } 21 | } 22 | 23 | class Person { 24 | constructor(firstName : string, lastName : string) { 25 | this.FirstName = firstName; 26 | this.LastName = lastName; 27 | } 28 | 29 | FirstName : string; 30 | LastName : string; 31 | } 32 | 33 | const ActivePerson = RecordStatus(Timestamp(Person)); 34 | 35 | let activePerson = new ActivePerson("Peter", "O'Hanlon"); 36 | activePerson.Updated = new Date(); 37 | activePerson.Delete(); 38 | 39 | 40 | console.log(`${activePerson.Deleted}`); -------------------------------------------------------------------------------- /Chapter01/Code/promises.ts: -------------------------------------------------------------------------------- 1 | // Promise only version of the asynchronous code. 2 | // function ExpensiveWebCall(time : number) : Promise { 3 | // return new Promise((resolve, reject) => setTimeout(resolve, time)); 4 | // } 5 | // class MyWebService { 6 | // CallExpensiveWebOperation() : void { 7 | // ExpensiveWebCall(4000).then(()=> console.log(`Finished web service`)) 8 | // .catch(()=> console.log(`Expensive web call failure`)); 9 | // } 10 | // } 11 | 12 | function ExpensiveWebCall(time : number) : Promise<{}> { 13 | return new Promise((resolve, reject) => setTimeout(resolve, time)); 14 | } 15 | class MyWebService { 16 | async CallExpensiveWebOperation() : Promise { 17 | try { 18 | ExpensiveWebCall(4000); 19 | console.log(`Finished web service`) 20 | } catch (error) { 21 | console.log(`Caught ${error}`); 22 | } 23 | } 24 | } 25 | 26 | 27 | console.log(`calling service`); 28 | new MyWebService().CallExpensiveWebOperation(); 29 | console.log(`Processing continues until the web service returns`); -------------------------------------------------------------------------------- /Chapter01/Code/type-aliases.ts: -------------------------------------------------------------------------------- 1 | export type StringOrNumber = string | number; 2 | import { RangeValidationBase } from "./union-types"; 3 | 4 | class UnionRangeValidationWithTypeAlias extends RangeValidationBase { 5 | IsInRange(value : StringOrNumber) : boolean { 6 | if (typeof value === "number") { 7 | return this.RangeCheck(value); 8 | } 9 | return this.RangeCheck(this.GetNumber(value)); 10 | } 11 | } 12 | 13 | let total : StringOrNumber = 10; 14 | if (new UnionRangeValidationWithTypeAlias(0,100).IsInRange(total)) { 15 | console.log(`This value is in range`); 16 | } -------------------------------------------------------------------------------- /Chapter01/Code/type-assertion.ts: -------------------------------------------------------------------------------- 1 | interface ElectricGuitar { 2 | numberOfPickups : number; 3 | } 4 | 5 | interface Violin { 6 | } 7 | 8 | function isElectricGuitar(v : Violin | ElectricGuitar) : v is ElectricGuitar { 9 | return (v).numberOfPickups !== undefined; 10 | } 11 | 12 | class Electric implements ElectricGuitar { 13 | numberOfPickups: number; 14 | constructor(numberOfPickups : number) { 15 | this.numberOfPickups = numberOfPickups; 16 | } 17 | } 18 | 19 | class MusicStore { 20 | BuyInstrument(instrument : ElectricGuitar | Violin) { 21 | if (isElectricGuitar(instrument)) { 22 | // Note that the backtick allows us to use the string formatting below... 23 | console.log(`Playing guitar with ${instrument.numberOfPickups} pickups`); 24 | } else { 25 | console.log(`This is a pretty cool violin`); 26 | } 27 | } 28 | } 29 | 30 | new MusicStore().BuyInstrument(new Electric(3)); -------------------------------------------------------------------------------- /Chapter01/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2015", 4 | "module": "commonjs", 5 | "lib": [ "ES2015", "dom" ], 6 | "sourceMap": true, 7 | "outDir": "./script", 8 | "strict": true, 9 | "strictNullChecks": true, 10 | "strictFunctionTypes": true, 11 | "noImplicitThis": true, 12 | "alwaysStrict": true, 13 | "noImplicitReturns": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "esModuleInterop": true, 16 | "experimentalDecorators": true, 17 | } 18 | } -------------------------------------------------------------------------------- /Chapter02/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2015", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "outDir": "./script", 7 | "strict": true, 8 | "strictNullChecks": true, 9 | "strictFunctionTypes": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "esModuleInterop": true, 15 | "experimentalDecorators": true, 16 | } 17 | } -------------------------------------------------------------------------------- /Chapter03/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /Chapter03/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}\\start", 12 | "outFiles": [ 13 | "${workspaceFolder}/**/*.js" 14 | ] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /Chapter03/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' 2 | declare module '*.png' 3 | declare module '*.jpg' 4 | declare module '*.jpeg' 5 | declare module '*.gif' 6 | declare module '*.bmp' 7 | declare module '*.tiff' 8 | -------------------------------------------------------------------------------- /Chapter03/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chapter03", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/bootstrap": "^4.1.2", 7 | "@types/reactstrap": "^6.4.3", 8 | "bootstrap": "^4.1.3", 9 | "react": "^16.6.3", 10 | "react-dom": "^16.6.3", 11 | "react-scripts-ts": "3.1.0", 12 | "reactstrap": "^6.5.0", 13 | "webpack-dev-server": "^3.2.1" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts-ts start", 17 | "build": "react-scripts-ts build", 18 | "test": "react-scripts-ts test --env=jsdom", 19 | "eject": "react-scripts-ts eject" 20 | }, 21 | "devDependencies": { 22 | "@types/jest": "^23.3.10", 23 | "@types/node": "^10.12.11", 24 | "@types/react": "^16.7.11", 25 | "@types/react-dom": "^16.0.11", 26 | "typescript": "^3.2.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter03/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter03/public/favicon.ico -------------------------------------------------------------------------------- /Chapter03/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter03/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-title { 18 | font-size: 1.5em; 19 | } 20 | 21 | .App-intro { 22 | font-size: large; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { transform: rotate(0deg); } 27 | to { transform: rotate(360deg); } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter03/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter03/src/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Container from 'reactstrap/lib/Container'; 3 | import './App.css'; 4 | import PersonalDetails from './PersonalDetails'; 5 | import { IPersonState } from "./State"; 6 | 7 | export default class App extends React.Component { 8 | private defaultPerson : IPersonState = { 9 | Address1: "", 10 | Address2: null, 11 | County: "", 12 | DateOfBirth : new Date().toISOString().substring(0,10), 13 | FirstName: "", 14 | LastName: "", 15 | PersonId : "", 16 | PhoneNumber: "", 17 | Postcode: "", 18 | Town: "" 19 | } 20 | constructor(props : {}) { 21 | super(props); 22 | } 23 | public render() { 24 | return ( 25 | 26 | 27 | 28 | ); 29 | } 30 | } -------------------------------------------------------------------------------- /Chapter03/src/PersonalDetailsTableBuilder.tsx: -------------------------------------------------------------------------------- 1 | import { TableBuilder } from './Database/TableBuilder'; 2 | 3 | export class PersonalDetailsTableBuilder { 4 | public Build() : TableBuilder { 5 | const tableBuilder : TableBuilder = new TableBuilder(); 6 | tableBuilder 7 | .WithDatabase("packt-advanced-typescript-ch3") 8 | .WithTableName("People") 9 | .WithPrimaryField("PersonId") 10 | .WithIndexName("personId") 11 | .WithVersion(1); 12 | return tableBuilder; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter03/src/RecordState.ts: -------------------------------------------------------------------------------- 1 | export interface IRecordState { 2 | IsActive : boolean; 3 | } 4 | 5 | export class RecordState implements IRecordState { 6 | public IsActive: boolean; 7 | } -------------------------------------------------------------------------------- /Chapter03/src/State.ts: -------------------------------------------------------------------------------- 1 | import { StringOrNull } from './Types'; 2 | 3 | export interface IPersonState { 4 | FirstName: string, 5 | LastName: string, 6 | Address1: string, 7 | Address2: StringOrNull, 8 | Town: string, 9 | County: string, 10 | PhoneNumber: string; 11 | Postcode: string, 12 | DateOfBirth: StringOrNull, 13 | PersonId : string 14 | } 15 | 16 | export class PersonState implements IPersonState { 17 | public FirstName: string; 18 | public LastName: string; 19 | public Address1: string; 20 | public Address2: StringOrNull; 21 | public Town: string; 22 | public County: string; 23 | public PersonId : string; 24 | public PhoneNumber: string; 25 | public Postcode: string; 26 | public DateOfBirth: StringOrNull; 27 | } 28 | -------------------------------------------------------------------------------- /Chapter03/src/Types.ts: -------------------------------------------------------------------------------- 1 | import { RecordState } from "./RecordState"; 2 | import { IPersonState } from './State'; 3 | 4 | export type PersonRecord = RecordState & IPersonState; 5 | export type StringOrNull = string | null; -------------------------------------------------------------------------------- /Chapter03/src/Validation/AddressValidation.ts: -------------------------------------------------------------------------------- 1 | import { IPersonState } from 'src/State'; 2 | import { MinLengthValidator } from 'src/Validators/MinLengthValidator'; 3 | import { RegularExpressionValidator } from 'src/Validators/RegularExpressionValidator'; 4 | import { IValidation } from './IValidation'; 5 | 6 | export class AddressValidation implements IValidation { 7 | private readonly minLengthValidator : MinLengthValidator = new MinLengthValidator(5); 8 | private readonly zipCodeValidator : RegularExpressionValidator = new RegularExpressionValidator("^[0-9]{5}(?:-[0-9]{4})?$"); 9 | public Validate(state: IPersonState, errors: string[]): void { 10 | if (!this.minLengthValidator.IsValid(state.Address1)) { 11 | errors.push("Address line 1 must be greater than 5 characters"); 12 | } 13 | if (!this.minLengthValidator.IsValid(state.Town)) { 14 | errors.push("Town must be greater than 5 characters"); 15 | } 16 | if (!this.minLengthValidator.IsValid(state.County)) { 17 | errors.push("County must be greater than 5 characters"); 18 | } 19 | if (!this.zipCodeValidator.IsValid(state.Postcode)) { 20 | errors.push("The postal/zip code is invalid"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Chapter03/src/Validation/IValidation.ts: -------------------------------------------------------------------------------- 1 | import { IPersonState } from 'src/State'; 2 | 3 | export interface IValidation { 4 | Validate(state : IPersonState, errors : string[]) : void; 5 | } -------------------------------------------------------------------------------- /Chapter03/src/Validation/PersonValidation.ts: -------------------------------------------------------------------------------- 1 | import { IPersonState } from 'src/State'; 2 | import { MinLengthValidator } from 'src/Validators/MinLengthValidator'; 3 | import { IValidation } from './IValidation'; 4 | 5 | export class PersonValidation implements IValidation { 6 | private readonly firstNameValidator : MinLengthValidator = new MinLengthValidator(1); 7 | private readonly lastNameValidator : MinLengthValidator = new MinLengthValidator(2); 8 | public Validate(state: IPersonState, errors: string[]): void { 9 | if (!this.firstNameValidator.IsValid(state.FirstName)) { 10 | errors.push("The first name is a minimum of 1 character"); 11 | } 12 | if (!this.lastNameValidator.IsValid(state.FirstName)) { 13 | errors.push("The last name is a minimum of 2 characters"); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Chapter03/src/Validation/PhoneValidation.ts: -------------------------------------------------------------------------------- 1 | import { IPersonState } from 'src/State'; 2 | import { MinLengthValidator } from 'src/Validators/MinLengthValidator'; 3 | import { RegularExpressionValidator } from 'src/Validators/RegularExpressionValidator'; 4 | import { IValidation } from './IValidation'; 5 | 6 | export class PhoneValidation implements IValidation { 7 | 8 | private readonly regexValidator : RegularExpressionValidator = new RegularExpressionValidator(`^(?:\\((?:[0-9]{3})\\)|(?:[0-9]{3}))[-. ]?(?:[0-9]{3})[-. ]?(?:[0-9]{4})$`); 9 | private readonly minLengthValidator : MinLengthValidator = new MinLengthValidator(1); 10 | 11 | public Validate(state : IPersonState, errors : string[]) : void { 12 | if (!this.minLengthValidator.IsValid(state.PhoneNumber)) { 13 | errors.push("You must enter a phone number") 14 | } else if (!this.regexValidator.IsValid(state.PhoneNumber)) { 15 | errors.push("The phone number format is invalid"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Chapter03/src/Validators/IValidator.ts: -------------------------------------------------------------------------------- 1 | interface IValidator { 2 | IsValid(input : T) : boolean; 3 | } -------------------------------------------------------------------------------- /Chapter03/src/Validators/MinLengthValidator.ts: -------------------------------------------------------------------------------- 1 | import { StringOrNull } from 'src/Types'; 2 | 3 | export class MinLengthValidator implements IValidator { 4 | private minLength : number; 5 | constructor(minLength : number) { 6 | this.minLength = minLength; 7 | } 8 | public IsValid(input : StringOrNull) : boolean { 9 | if (!input) { 10 | return false; 11 | } 12 | return input.length >= this.minLength; 13 | } 14 | } -------------------------------------------------------------------------------- /Chapter03/src/Validators/RegularExpressionValidator.ts: -------------------------------------------------------------------------------- 1 | import { StringOrNull } from 'src/Types'; 2 | 3 | export class RegularExpressionValidator implements IValidator { 4 | private regex : RegExp; 5 | constructor(expression : string) { 6 | this.regex = new RegExp(expression); 7 | } 8 | public IsValid (input : StringOrNull) : boolean { 9 | if (!input) { 10 | return false; 11 | } 12 | return this.regex.test(input); 13 | } 14 | } -------------------------------------------------------------------------------- /Chapter03/src/index.tsx: -------------------------------------------------------------------------------- 1 | // Import bootstrap before any other imports 2 | import "bootstrap/dist/css/bootstrap.min.css"; 3 | import * as React from 'react'; 4 | import * as ReactDOM from 'react-dom'; 5 | import App from './App'; 6 | import registerServiceWorker from './registerServiceWorker'; 7 | 8 | ReactDOM.render( 9 | , 10 | document.getElementById('root') as HTMLElement 11 | ); 12 | registerServiceWorker(); 13 | -------------------------------------------------------------------------------- /Chapter03/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "outDir": "build/dist", 5 | "module": "esnext", 6 | "target": "es2016", 7 | "lib": [ 8 | "es6", 9 | "dom" 10 | ], 11 | "sourceMap": true, 12 | "allowJs": true, 13 | "jsx": "react", 14 | "moduleResolution": "node", 15 | "rootDir": "src", 16 | "forceConsistentCasingInFileNames": true, 17 | "noImplicitReturns": true, 18 | "noImplicitThis": true, 19 | "noImplicitAny": true, 20 | "importHelpers": true, 21 | "strictNullChecks": true, 22 | "suppressImplicitAnyIndexErrors": true, 23 | "noUnusedLocals": true, 24 | "experimentalDecorators": true, 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "build", 29 | "scripts", 30 | "acceptance-tests", 31 | "webpack", 32 | "jest", 33 | "src/setupTests.ts" 34 | ] 35 | } -------------------------------------------------------------------------------- /Chapter03/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } -------------------------------------------------------------------------------- /Chapter03/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } -------------------------------------------------------------------------------- /Chapter03/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "linterOptions": { 4 | "exclude": [ 5 | "config/**/*.js", 6 | "node_modules/**/*.ts", 7 | "coverage/lcov-report/*.js" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter04/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "build", 9 | "path": "Server/", 10 | "problemMatcher": [ 11 | "$tslint5" 12 | ] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /Chapter04/Client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /Chapter04/Client/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # profiling files 12 | chrome-profiler-events.json 13 | speed-measure-plugin.json 14 | 15 | # IDEs and editors 16 | /.idea 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # IDE - VSCode 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | .history/* 31 | 32 | # misc 33 | /.sass-cache 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | npm-debug.log 38 | yarn-error.log 39 | testem.log 40 | /typings 41 | 42 | # System Files 43 | .DS_Store 44 | Thumbs.db 45 | -------------------------------------------------------------------------------- /Chapter04/Client/README.md: -------------------------------------------------------------------------------- 1 | # Chapter04 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /Chapter04/Client/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /Chapter04/Client/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to Chapter04!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | })); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Chapter04/Client/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('atp-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter04/Client/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter04/Client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Menu 4 | 5 | Import image 6 | 7 | 8 | 9 | 10 | 13 | Advanced TypeScript 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | >>> body { 2 | margin: 0; 3 | } 4 | 5 | main { 6 | margin: 30px; 7 | } 8 | 9 | .toolbar-filler { 10 | flex: 1 1 auto 11 | } -------------------------------------------------------------------------------- /Chapter04/Client/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'Chapter04'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('Chapter04'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to Chapter04!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { MatDialog, MatDialogRef, MatDialogConfig } from '@angular/material'; 3 | import { FileuploadComponent } from './components/fileupload/fileupload.component'; 4 | import { AddImageService } from './services/add-image.service'; 5 | 6 | @Component({ 7 | selector: 'atp-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.scss'] 10 | }) 11 | export class AppComponent { 12 | private dialogRef: MatDialogRef | null = null; 13 | constructor(private dialog: MatDialog, private addImage: AddImageService) { 14 | 15 | } 16 | 17 | public ImportImage(): void { 18 | const config = new MatDialogConfig(); 19 | config.disableClose = true; 20 | config.autoFocus = true; 21 | config.width = '500px'; 22 | this.dialogRef = this.dialog.open(FileuploadComponent, config); 23 | this.dialogRef.afterClosed().subscribe(r => { 24 | if (r) { 25 | this.addImage.add(r); 26 | } 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/components/fileupload/fileupload.component.html: -------------------------------------------------------------------------------- 1 |

Choose image

2 | 3 |

{{message}}

4 | 5 | 6 |
7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/components/fileupload/fileupload.component.scss: -------------------------------------------------------------------------------- 1 | .mat-form-field { 2 | display: block; 3 | } 4 | 5 | textarea { 6 | height: 100px; 7 | resize: vertical; 8 | } -------------------------------------------------------------------------------- /Chapter04/Client/src/app/components/fileupload/fileupload.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FileuploadComponent } from './fileupload.component'; 4 | 5 | describe('FileuploadComponent', () => { 6 | let component: FileuploadComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FileuploadComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FileuploadComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/components/page-body/page-body.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{picture.Name}} 5 | 6 | 7 |

{{picture.Description}}

8 |
9 |
10 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/components/page-body/page-body.component.scss: -------------------------------------------------------------------------------- 1 | .picture-card-layout { 2 | width: 25%; 3 | margin-top: 2%; 4 | margin-bottom: 2%; 5 | } -------------------------------------------------------------------------------- /Chapter04/Client/src/app/components/page-body/page-body.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageBodyComponent } from './page-body.component'; 4 | 5 | describe('PageBodyComponent', () => { 6 | let component: PageBodyComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PageBodyComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageBodyComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/ContextServiceBase.ts: -------------------------------------------------------------------------------- 1 | import { BehaviorSubject } from 'rxjs'; 2 | import { IPictureModel } from '../types'; 3 | export class ContextServiceBase { 4 | private source = new BehaviorSubject(null); 5 | constructor() { } 6 | context = this.source.asObservable(); 7 | public add(image: IPictureModel): void { 8 | this.source.next(image); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/add-image.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AddImageService } from './add-image.service'; 4 | 5 | describe('AddImageService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: AddImageService = TestBed.get(AddImageService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/add-image.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ContextServiceBase } from './ContextServiceBase'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class AddImageService extends ContextServiceBase { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/file-preview-service.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { FilePreviewService } from './file-preview-service.service'; 4 | 5 | describe('FilePreviewService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: FilePreviewService = TestBed.get(FilePreviewService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/file-preview-service.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { IPictureModel, PictureModel } from '../types'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class FilePreviewService { 8 | public Preview(files: any): Promise { 9 | return new Promise((resolve, reject) => { 10 | if (files.length === 0) { 11 | return; 12 | } 13 | const file = files[0]; 14 | if (file.type.match(/image\/*/) === null) { 15 | reject(`The file is not an image file.`); 16 | return; 17 | } 18 | const imageModel: IPictureModel = new PictureModel(); 19 | imageModel.Name = file.name; 20 | const reader = new FileReader(); 21 | reader.onload = (evt) => { 22 | imageModel.Image = reader.result; 23 | resolve(imageModel); 24 | }; 25 | reader.readAsDataURL(file); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/load-image.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadImageService } from './load-image.service'; 4 | 5 | describe('LoadImageService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: LoadImageService = TestBed.get(LoadImageService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/load-image.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ContextServiceBase } from './ContextServiceBase'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class LoadImageService extends ContextServiceBase { 8 | 9 | } 10 | 11 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/services/transfer-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { TransferDataService } from './transfer-data.service'; 4 | 5 | describe('TransferDataService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: TransferDataService = TestBed.get(TransferDataService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter04/Client/src/app/types.ts: -------------------------------------------------------------------------------- 1 | export type ImageType = string | ArrayBuffer; 2 | 3 | export interface IPictureModel { 4 | Image: ImageType; 5 | Name: string; 6 | Description: string; 7 | Tags: string; 8 | } 9 | 10 | export class PictureModel implements IPictureModel { 11 | Image: ImageType; 12 | Name: string; 13 | Description: string; 14 | Tags: string; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter04/Client/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter04/Client/src/assets/.gitkeep -------------------------------------------------------------------------------- /Chapter04/Client/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /Chapter04/Client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /Chapter04/Client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /Chapter04/Client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter04/Client/src/favicon.ico -------------------------------------------------------------------------------- /Chapter04/Client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Advanced TypeScript - Photo Gallery 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Chapter04/Client/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /Chapter04/Client/src/main.ts: -------------------------------------------------------------------------------- 1 | import 'hammerjs'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | import { environment } from './environments/environment'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /Chapter04/Client/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | -------------------------------------------------------------------------------- /Chapter04/Client/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /Chapter04/Client/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Chapter04/Client/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Chapter04/Client/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "atp", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "atp", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter04/Client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter04/Server/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /Chapter04/Server/AdvancedTypeScriptProjectsChapter4.ts: -------------------------------------------------------------------------------- 1 | import { RoutingEngine } from "./Routing/RoutingEngine"; 2 | import { AddPictureRouter } from "./Routing/AddRouter"; 3 | import { GetPicturesRouter } from "./Routing/GetPicturesRouter"; 4 | import { FindByIdRouter } from "./Routing/FindByIdRouter"; 5 | import { Server } from "./server"; 6 | export class AdvancedTypeScriptProjectsChapter4 extends Server { 7 | protected AddRouting(routingEngine: RoutingEngine, router: any): void { 8 | routingEngine.Add(AddPictureRouter, router); 9 | routingEngine.Add(GetPicturesRouter, router); 10 | routingEngine.Add(FindByIdRouter, router); 11 | } 12 | } 13 | 14 | new AdvancedTypeScriptProjectsChapter4(3000).WithCorsSupport().Start(); -------------------------------------------------------------------------------- /Chapter04/Server/Database.ts: -------------------------------------------------------------------------------- 1 | import mongoose, { Schema } from "mongoose"; 2 | 3 | export class Mongo { 4 | constructor(private url : string = "mongodb://localhost:27017/packt_atp_chapter_04") { 5 | } 6 | 7 | public Connect(): void { 8 | mongoose.connect(this.url, (e:any) => { 9 | if (e) { 10 | console.log(`Unable to connect ` + e); 11 | } else { 12 | console.log(`Connected to the database`); 13 | } 14 | }); 15 | } 16 | } 17 | 18 | export const PictureSchema = new Schema({ 19 | Image: String, 20 | Name: String, 21 | Description: String, 22 | Tags: String, 23 | }); 24 | 25 | export const Picture = mongoose.model('picture', PictureSchema); 26 | -------------------------------------------------------------------------------- /Chapter04/Server/README: -------------------------------------------------------------------------------- 1 | tsc --init 2 | npm init -y // creates package.json 3 | npm install express mongoose cors multer --save 4 | -------------------------------------------------------------------------------- /Chapter04/Server/Routing/AddRouter.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "./Router"; 2 | import { Picture } from "../Database"; 3 | import { Response } from "express"; 4 | 5 | export class AddPictureRouter implements IRouter { 6 | public AddRoute(route: any): void { 7 | route.post('/add/', (request: Request, response: Response) => { 8 | const picture = new Picture(request.body); 9 | picture.save((err: any, picture: any) => { 10 | if (err) { 11 | response.send(err); 12 | } 13 | response.json(picture); 14 | }); 15 | }); 16 | } 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /Chapter04/Server/Routing/FindByIdRouter.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "./Router"; 2 | import { Picture } from "../Database"; 3 | import { Request, Response } from "express"; 4 | 5 | export class FindByIdRouter implements IRouter { 6 | public AddRoute(route: any): void { 7 | route.get('/id/:id', (request: Request, response: Response) => { 8 | Picture.findOne({ _id: request.params.id }, '-_id', (err: any, picture: any) => { 9 | if (err) { 10 | response.send(err); 11 | } 12 | response.json(picture); 13 | }); 14 | }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter04/Server/Routing/GetPicturesRouter.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "./Router"; 2 | import { Picture } from "../Database"; 3 | import { Response } from "express"; 4 | export class GetPicturesRouter implements IRouter { 5 | public AddRoute(route: any): void { 6 | route.get('/get/', (request: Request, response: Response) => { 7 | Picture.distinct("_id", (err: any, picture: any) => { 8 | if (err) { 9 | response.send(err); 10 | } 11 | response.send(picture); 12 | }); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter04/Server/Routing/Router.ts: -------------------------------------------------------------------------------- 1 | export interface IRouter { 2 | AddRoute(route: any): void; 3 | } 4 | -------------------------------------------------------------------------------- /Chapter04/Server/Routing/Routes.ts: -------------------------------------------------------------------------------- 1 | import { AddPictureRouter } from "./AddRouter"; 2 | import { FindByIdRouter } from "./FindByIdRouter"; 3 | import { GetPicturesRouter } from "./GetPicturesRouter"; 4 | import { RoutingEngine } from "./RoutingEngine"; 5 | export class Routes { 6 | constructor(private router: any, private routingEngine: RoutingEngine = new RoutingEngine()) { 7 | } 8 | public AddRoutes(): void { 9 | this.routingEngine.Add(AddPictureRouter, this.router); 10 | this.routingEngine.Add(GetPicturesRouter, this.router); 11 | this.routingEngine.Add(FindByIdRouter, this.router); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter04/Server/Routing/RoutingEngine.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "./Router"; 2 | export class RoutingEngine { 3 | constructor(private routing: IRouter[] = new Array()) { 4 | } 5 | public Add(routing: (new () => T1), route: any) { 6 | const routed = new routing(); 7 | routed.AddRoute(route); 8 | this.routing.push(routed); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/AdvancedTypeScriptProjectsChapter4.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const AddRouter_1 = require("./Routing/AddRouter"); 4 | const GetPicturesRouter_1 = require("./Routing/GetPicturesRouter"); 5 | const FindByIdRouter_1 = require("./Routing/FindByIdRouter"); 6 | const server_1 = require("./server"); 7 | class AdvancedTypeScriptProjectsChapter4 extends server_1.Server { 8 | AddRouting(routingEngine, router) { 9 | routingEngine.Add(AddRouter_1.AddPictureRouter, router); 10 | routingEngine.Add(GetPicturesRouter_1.GetPicturesRouter, router); 11 | routingEngine.Add(FindByIdRouter_1.FindByIdRouter, router); 12 | } 13 | } 14 | exports.AdvancedTypeScriptProjectsChapter4 = AdvancedTypeScriptProjectsChapter4; 15 | new AdvancedTypeScriptProjectsChapter4(3000).WithCorsSupport().Start(); 16 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Database.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importStar = (this && this.__importStar) || function (mod) { 3 | if (mod && mod.__esModule) return mod; 4 | var result = {}; 5 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; 6 | result["default"] = mod; 7 | return result; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | const mongoose_1 = __importStar(require("mongoose")); 11 | class Mongo { 12 | constructor(url = "mongodb://localhost:27017/packt_atp_chapter_04") { 13 | this.url = url; 14 | } 15 | Connect() { 16 | mongoose_1.default.connect(this.url, (e) => { 17 | if (e) { 18 | console.log(`Unable to connect ` + e); 19 | } 20 | else { 21 | console.log(`Connected to the database`); 22 | } 23 | }); 24 | } 25 | } 26 | exports.Mongo = Mongo; 27 | exports.PictureSchema = new mongoose_1.Schema({ 28 | Image: String, 29 | Name: String, 30 | Description: String, 31 | Tags: String, 32 | }); 33 | exports.Picture = mongoose_1.default.model('picture', exports.PictureSchema); 34 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Router.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | class Router { 4 | } 5 | exports.Router = Router; 6 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Routing/AddRouter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Database_1 = require("../Database"); 4 | class AddPictureRouter { 5 | AddRoute(route) { 6 | route.post('/add/', (request, response) => { 7 | const picture = new Database_1.Picture(request.body); 8 | picture.save((err, picture) => { 9 | if (err) { 10 | response.send(err); 11 | } 12 | response.json(picture); 13 | }); 14 | }); 15 | } 16 | } 17 | exports.AddPictureRouter = AddPictureRouter; 18 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Routing/FindByIdRouter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Database_1 = require("../Database"); 4 | class FindByIdRouter { 5 | AddRoute(route) { 6 | route.get('/id/:id', (request, response) => { 7 | Database_1.Picture.findOne({ _id: request.params.id }, '-_id', (err, picture) => { 8 | if (err) { 9 | response.send(err); 10 | } 11 | response.json(picture); 12 | }); 13 | }); 14 | } 15 | } 16 | exports.FindByIdRouter = FindByIdRouter; 17 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Routing/GetPicturesRouter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Database_1 = require("../Database"); 4 | class GetPicturesRouter { 5 | AddRoute(route) { 6 | route.get('/get/', (request, response) => { 7 | Database_1.Picture.distinct("_id", (err, picture) => { 8 | if (err) { 9 | response.send(err); 10 | } 11 | response.send(picture); 12 | }); 13 | }); 14 | } 15 | } 16 | exports.GetPicturesRouter = GetPicturesRouter; 17 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Routing/Router.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Routing/Routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const AddRouter_1 = require("./AddRouter"); 4 | const FindByIdRouter_1 = require("./FindByIdRouter"); 5 | const GetPicturesRouter_1 = require("./GetPicturesRouter"); 6 | const RoutingEngine_1 = require("./RoutingEngine"); 7 | class Routes { 8 | constructor(router, routingEngine = new RoutingEngine_1.RoutingEngine()) { 9 | this.router = router; 10 | this.routingEngine = routingEngine; 11 | } 12 | AddRoutes() { 13 | this.routingEngine.Add(AddRouter_1.AddPictureRouter, this.router); 14 | this.routingEngine.Add(GetPicturesRouter_1.GetPicturesRouter, this.router); 15 | this.routingEngine.Add(FindByIdRouter_1.FindByIdRouter, this.router); 16 | } 17 | } 18 | exports.Routes = Routes; 19 | -------------------------------------------------------------------------------- /Chapter04/Server/dist/Routing/RoutingEngine.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | class RoutingEngine { 4 | constructor(routing = new Array()) { 5 | this.routing = routing; 6 | } 7 | Add(routing, route) { 8 | const routed = new routing(); 9 | routed.AddRoute(route); 10 | this.routing.push(routed); 11 | } 12 | } 13 | exports.RoutingEngine = RoutingEngine; 14 | -------------------------------------------------------------------------------- /Chapter04/Server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "AdvancedTypeScriptProjectsChapter4.js", 6 | "scripts": { 7 | "start": "nodemon dist/AdvancedTypeScriptProjectsChapter4.js", 8 | "build": "tsc" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@types/cors": "^2.8.4", 15 | "body-parser": "^1.18.3", 16 | "cors": "^2.8.5", 17 | "express": "^4.16.4", 18 | "mongoose": "^5.4.8", 19 | "multer": "^1.4.1", 20 | "npm": "^6.9.2" 21 | }, 22 | "devDependencies": { 23 | "@types/body-parser": "^1.17.0", 24 | "@types/express": "^4.16.0", 25 | "@types/mongodb": "^3.1.19", 26 | "@types/mongoose": "^5.3.11", 27 | "nodemon": "^1.18.4", 28 | "ts-node": "^7.0.1", 29 | "typescript": "^3.0.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Chapter04/Server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "outDir": "./dist", 6 | "strict": true, 7 | "allowSyntheticDefaultImports": true, 8 | "composite": true, 9 | "esModuleInterop": true 10 | }, 11 | } -------------------------------------------------------------------------------- /Chapter05/.idea/Chapter05.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Chapter05/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /Chapter05/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /Chapter05/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter05/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Chapter05/Client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /Chapter05/Client/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | /dist 11 | 12 | # profiling files 13 | chrome-profiler-events.json 14 | speed-measure-plugin.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | yarn-error.log 40 | testem.log 41 | /typings 42 | 43 | # System Files 44 | .DS_Store 45 | Thumbs.db 46 | -------------------------------------------------------------------------------- /Chapter05/Client/README.md: -------------------------------------------------------------------------------- 1 | # Chapter05 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /Chapter05/Client/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /Chapter05/Client/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to Chapter05!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | })); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Chapter05/Client/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('atp-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter05/Client/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter05/Client/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { AlltasksComponent } from './components/alltasks/alltasks.component'; 4 | import { AddTaskComponent } from './components/add-task/add-task.component'; 5 | import { OverduetasksComponent } from './components/overduetasks/overduetasks.component'; 6 | 7 | const routes: Routes = [{ 8 | path: '', 9 | redirectTo: 'all', 10 | pathMatch: 'full' 11 | }, 12 | { 13 | path: 'all', 14 | component: AlltasksComponent 15 | }, 16 | { 17 | path: 'add', 18 | component: AddTaskComponent 19 | }, 20 | { 21 | path: 'overdue', 22 | component: OverduetasksComponent 23 | }]; 24 | 25 | @NgModule({ 26 | imports: [RouterModule.forRoot(routes)], 27 | exports: [RouterModule] 28 | }) 29 | export class AppRoutingModule { } 30 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | All tasks 3 | Overdue tasks 4 | Add task 5 | 6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | a:hover, a:active { 2 | color: lightgreen; 3 | } 4 | 5 | .mat-list-item { 6 | color: white; 7 | } -------------------------------------------------------------------------------- /Chapter05/Client/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'atp-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'Advanced TypeScript 3 - ToDo'; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/add-task/add-task.component.scss: -------------------------------------------------------------------------------- 1 | .centerDiv{ 2 | height: 100vh; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | } 7 | 8 | .mat-card { 9 | width: 400px; 10 | } 11 | .mat-form-field { 12 | display: block; 13 | } 14 | 15 | textarea { 16 | height: 100px; 17 | resize: vertical; 18 | } -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/add-task/add-task.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AddTaskComponent } from './add-task.component'; 4 | 5 | describe('AddTaskComponent', () => { 6 | let component: AddTaskComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AddTaskComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AddTaskComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/alltasks/alltasks.component.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/alltasks/alltasks.component.scss: -------------------------------------------------------------------------------- 1 | .tasks-card-layout { 2 | width: 25%; 3 | margin-top: 2%; 4 | margin-bottom: 2%; 5 | } 6 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/alltasks/alltasks.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AlltasksComponent } from './alltasks.component'; 4 | 5 | describe('AlltasksComponent', () => { 6 | let component: AlltasksComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AlltasksComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AlltasksComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/alltasks/alltasks.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { map } from 'rxjs/operators'; 3 | import { Apollo } from 'apollo-angular'; 4 | 5 | import gql from 'graphql-tag'; 6 | import { ITodoItem } from '../../../../../Common/models/TodoItem'; 7 | import { TodoItemQuery } from '../../types/TodoItemQuery'; 8 | import { SubscriptionBase } from 'src/app/types/SubscriptionBase'; 9 | 10 | @Component({ 11 | selector: 'atp-alltasks', 12 | templateUrl: './alltasks.component.html', 13 | styleUrls: ['./alltasks.component.scss'] 14 | }) 15 | 16 | export class AlltasksComponent extends SubscriptionBase implements OnInit { 17 | 18 | constructor(apollo: Apollo) { 19 | super(apollo); 20 | } 21 | 22 | ngOnInit() { 23 | this.Subscribe(gql`query ItemsQuery { 24 | TodoItems { 25 | Id, 26 | Title, 27 | Description, 28 | DaysCreated, 29 | DueDate, 30 | Completed 31 | } 32 | }`).subscribe(todo => { 33 | this.todos = new Array(); 34 | todo.data.TodoItems.forEach(x => { 35 | this.todos.push(x); 36 | }); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/overduetasks/overduetasks.component.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/overduetasks/overduetasks.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter05/Client/src/app/components/overduetasks/overduetasks.component.scss -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/overduetasks/overduetasks.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OverduetasksComponent } from './overduetasks.component'; 4 | 5 | describe('OverduetasksComponent', () => { 6 | let component: OverduetasksComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ OverduetasksComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OverduetasksComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/todo-card/todo-card.component.scss: -------------------------------------------------------------------------------- 1 | .mat-card { 2 | width: 400px; 3 | } 4 | .mat-form-field { 5 | display: block; 6 | } 7 | 8 | textarea, .descriptionBlock { 9 | height: 100px; 10 | resize: vertical; 11 | } -------------------------------------------------------------------------------- /Chapter05/Client/src/app/components/todo-card/todo-card.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { TodoCardComponent } from './todo-card.component'; 4 | 5 | describe('TodoCardComponent', () => { 6 | let component: TodoCardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ TodoCardComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(TodoCardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/types/SubscriptionBase.ts: -------------------------------------------------------------------------------- 1 | import { ITodoItem } from '../../../../Common/models/TodoItem'; 2 | import { Apollo } from 'apollo-angular'; 3 | import { OverdueTodoItemQuery, TodoItemQuery } from 'src/app/types/TodoItemQuery'; 4 | import { Observable } from 'rxjs'; 5 | import { ApolloQueryResult } from 'apollo-client'; 6 | export class SubscriptionBase { 7 | todos: ITodoItem[] = new Array(); 8 | constructor(private apollo: Apollo) { 9 | } 10 | protected Subscribe(gqlQuery: unknown): Observable> { 11 | return this.apollo.query({ 12 | query: gqlQuery, 13 | fetchPolicy: 'no-cache' 14 | }); 15 | } 16 | resubscribe = (event: string) => { 17 | const index = this.todos.findIndex(x => x.Id === event); 18 | this.todos.splice(index, 1); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/types/TodoItemInput.ts: -------------------------------------------------------------------------------- 1 | import { ITodoItemInput } from '../../../../Common/models/ITodoItemInput'; 2 | export class TodoItemInput implements ITodoItemInput { 3 | Id: string; 4 | Title: string; 5 | Description?: string; 6 | DueDate: Date; 7 | CreationDate: Date; 8 | Completed: boolean; 9 | } 10 | -------------------------------------------------------------------------------- /Chapter05/Client/src/app/types/TodoItemQuery.ts: -------------------------------------------------------------------------------- 1 | import { ITodoItem } from '../../../../Common/models/TodoItem'; 2 | 3 | export interface TodoItemQuery { 4 | // The name of the property is going to map back to the name in the query 5 | TodoItems: ITodoItem[]; 6 | } 7 | 8 | export interface OverdueTodoItemQuery { 9 | OverdueTodoItems: ITodoItem[]; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter05/Client/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter05/Client/src/assets/.gitkeep -------------------------------------------------------------------------------- /Chapter05/Client/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /Chapter05/Client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /Chapter05/Client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /Chapter05/Client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter05/Client/src/favicon.ico -------------------------------------------------------------------------------- /Chapter05/Client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Advanced TypeScript 3 - ToDo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Chapter05/Client/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /Chapter05/Client/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /Chapter05/Client/src/models/ITodoItemInput.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /Chapter05/Client/src/models/TodoItem.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /Chapter05/Client/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | -------------------------------------------------------------------------------- /Chapter05/Client/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /Chapter05/Client/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Chapter05/Client/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Chapter05/Client/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "atp", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "atp", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter05/Client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "composite": false, 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ], 18 | "lib": [ 19 | "es2018", 20 | "dom" 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Chapter05/Common/models/ITodoItemInput.ts: -------------------------------------------------------------------------------- 1 | import { ITodoItem } from "./TodoItem"; 2 | export interface ITodoItemInput extends ITodoItem { 3 | CreationDate?: Date; 4 | } -------------------------------------------------------------------------------- /Chapter05/Common/models/TodoItem.ts: -------------------------------------------------------------------------------- 1 | export interface ITodoItem { 2 | Id: string; 3 | Title: string; 4 | Description?: string; 5 | DueDate?: Date; 6 | Completed: boolean; 7 | } 8 | -------------------------------------------------------------------------------- /Chapter05/Server/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /Chapter05/Server/apolloserver.ts: -------------------------------------------------------------------------------- 1 | // Very important - reflect metadata needs to be at the top of the stack of imports 2 | import { ApolloServer } from "apollo-server"; 3 | import * as path from "path"; 4 | import { buildSchema } from "type-graphql"; 5 | import { TodoItemResolver } from "./graph/TodoItemResolver"; 6 | import { Prefill } from "./graph/Prefill"; 7 | import { Mongo } from "./database/Database"; 8 | import { GraphQLSchema } from "graphql"; 9 | 10 | export class MyApp { 11 | 12 | constructor(private mongo: Mongo = new Mongo()) { } 13 | 14 | public async Start(): Promise { 15 | this.mongo.Connect(); 16 | 17 | const schema: GraphQLSchema = await buildSchema({ 18 | resolvers: [TodoItemResolver], 19 | validate: false, 20 | emitSchemaFile: path.resolve(__dirname, 'apolloschema.gql') 21 | }); 22 | 23 | // GraphQL uses lazy loading. In order to respond to our clients faster, we're going to pre-populate this 24 | // list. 25 | await Prefill.Instance.Populate(); 26 | 27 | const server = new ApolloServer({ schema, playground: true }); 28 | await server.listen(3000); 29 | } 30 | } 31 | 32 | new MyApp().Start(); -------------------------------------------------------------------------------- /Chapter05/Server/database/Database.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | export class Mongo { 4 | constructor(private url : string = "mongodb://localhost:27017/packt_atp_chapter_05") { 5 | } 6 | 7 | public Connect(): void { 8 | mongoose.connect(this.url, { useNewUrlParser: true}, (e:unknown) => { 9 | if (e) { 10 | console.log(`Unable to connect ` + e); 11 | } else { 12 | console.log(`Connected to the database`); 13 | } 14 | }); 15 | } 16 | } 17 | 18 | export type Model = mongoose.Model -------------------------------------------------------------------------------- /Chapter05/Server/database/Schema.ts: -------------------------------------------------------------------------------- 1 | import mongoose, { Schema } from "mongoose"; 2 | 3 | export interface ITodoSchema extends mongoose.Document { 4 | Id: string, 5 | Title: string, 6 | Description: string, 7 | DueDate: Date, 8 | CreationDate: Date, 9 | Completed: boolean, 10 | } 11 | 12 | export const TodoSchema = new Schema({ 13 | Id: String, 14 | Title: String, 15 | Description: String, 16 | DueDate: Date, 17 | CreationDate: Date, 18 | Completed: Boolean, 19 | }); 20 | 21 | export const TodoModel = mongoose.model('todo', TodoSchema, 'todoitems', false); -------------------------------------------------------------------------------- /Chapter05/Server/database/TodoDataAccess.ts: -------------------------------------------------------------------------------- 1 | import { ITodoSchema, TodoModel } from "./Schema"; 2 | import { DataAccessBase } from "./DataAccessBase"; 3 | export class TodoDataAccess extends DataAccessBase { 4 | constructor() { 5 | super(TodoModel); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Chapter05/Server/graph/TodoItem.ts: -------------------------------------------------------------------------------- 1 | import { Field, ID, ObjectType, Int } from "type-graphql"; 2 | 3 | @ObjectType({ description: "A single to do" }) 4 | export class TodoItem { 5 | constructor() { 6 | this.Completed = false; 7 | } 8 | @Field(type=>ID) 9 | Id: string = ""; 10 | 11 | @Field() 12 | Title: string; 13 | 14 | @Field({ nullable: true, description: "The description of the item." }) 15 | Description?: string; 16 | 17 | @Field({ nullable: true, description: "The due date for the item" }) 18 | DueDate?: Date; 19 | 20 | @Field({ nullable: true, description: "The date the item was created" }) 21 | CreationDate: Date; 22 | 23 | @Field(type => Int) 24 | DaysCreated: number; 25 | 26 | @Field() 27 | Completed: boolean; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter05/Server/graph/TodoItemInput.ts: -------------------------------------------------------------------------------- 1 | import { Field, InputType, ID } from "type-graphql"; 2 | import { TodoItem } from "./TodoItem"; 3 | 4 | @InputType() 5 | export class TodoItemInput implements Partial { 6 | @Field() 7 | Id: string; 8 | @Field({description: "The item title"}) 9 | Title: string = ""; 10 | @Field({ nullable: true, description: "The item description" }) 11 | Description?: string = ""; 12 | @Field({ nullable: true, description: "The item due date" }) 13 | DueDate?: Date; 14 | @Field() 15 | CreationDate: Date; 16 | @Field() 17 | Completed: boolean = false; 18 | } 19 | -------------------------------------------------------------------------------- /Chapter05/Server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-item-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./dist/apolloserver.js", 6 | "scripts": { 7 | "start": "nodemon dist/apolloserver.js", 8 | "build": "tsc" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@types/body-parser": "^1.17.0", 15 | "@types/express": "^4.16.1", 16 | "@types/graphql": "^14.0.7", 17 | "@types/mongoose": "^5.3.20", 18 | "apollo-server": "^2.4.0", 19 | "apollo-server-express": "^2.4.0", 20 | "class-transformer": "^0.2.0", 21 | "express": "^4.16.4", 22 | "guid-typescript": "^1.0.9", 23 | "mongoose": "^5.4.16", 24 | "nodemon": "^1.18.10", 25 | "parser": "^0.1.4", 26 | "reflect-metadata": "^0.1.13", 27 | "type-graphql": "^0.16.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Chapter05/Server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "target": "es2016", 5 | "module": "commonjs", 6 | "lib": ["es2016", "esnext.asynciterable", "dom"], 7 | "outDir": "./dist", 8 | "noImplicitAny": true, 9 | "esModuleInterop": true, 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter06/.idea/Chapter06.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Chapter06/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /Chapter06/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /Chapter06/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /Chapter06/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /Chapter06/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter06/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Chapter06/Client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /Chapter06/Client/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /Chapter06/Client/README.md: -------------------------------------------------------------------------------- 1 | # Client notes 2 | 3 | This application uses Auth0 to provide authentication. While there is a sample endpoint in oauth-authorization.service.ts, this is not live details so you will need to supply your own. In the book, I talk about how you need to sign up to the Auth0 but this is a quick recap. 4 | 5 | When you have signed up, you will need to copy your client id and replace the clientID entry with the one you create. You may also need to replace the domain with the Auth0 domain if you are using a different location. 6 | 7 | In Auth0, you will also need to set up the Allowed Callbacks URL, this is not provided for you - here I have defaulted this to http://localhost:4200/callback in the redirectUrl in the authorization service. If you change this to a different endpoint, you must change the value in both the redirectUrl AND the authorization service. 8 | 9 | When you log out of Auth0, Auth0 needs to know where to redirect you to. You supply this value in the Allowed Logout URLs. I typically default this back to the application default page. -------------------------------------------------------------------------------- /Chapter06/Client/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /Chapter06/Client/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to Client!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Chapter06/Client/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter06/Client/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter06/Client/src/app/Types/Logging.ts: -------------------------------------------------------------------------------- 1 | export function Log() { 2 | return function(target: Object, 3 | propertyName: string, 4 | propertyDesciptor: PropertyDescriptor): PropertyDescriptor { 5 | const method = propertyDesciptor.value; 6 | propertyDesciptor.value = function(...args: unknown[]) { 7 | const params = args.map(arg => JSON.stringify(arg)).join(); 8 | const result = method.apply(this, args); 9 | if (args && args.length > 0) { 10 | console.log(`Calling ${propertyName} with ${params}`); 11 | } else { 12 | console.log(`Calling ${propertyName}. No parameters present.`) 13 | } 14 | return result; 15 | }; 16 | return propertyDesciptor; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/Types/user.logon.ts: -------------------------------------------------------------------------------- 1 | export class UserLogon { 2 | user: string; 3 | time: Date 4 | } 5 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import {GeneralchatComponent} from "./components/generalchat/generalchat.component"; 4 | import {SecretchatComponent} from "./components/secretchat/secretchat.component"; 5 | import {AuthorizationService} from "./services/authorization.service"; 6 | 7 | const routes: Routes = [{ 8 | path: '', 9 | redirectTo: 'general', 10 | pathMatch: 'full' 11 | }, { 12 | path: 'general', 13 | component: GeneralchatComponent 14 | }, { 15 | path: 'secret', 16 | component: SecretchatComponent, 17 | canActivate: [AuthorizationService] 18 | }]; 19 | 20 | @NgModule({ 21 | imports: [RouterModule.forRoot(routes)], 22 | exports: [RouterModule] 23 | }) 24 | export class AppRoutingModule { } 25 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | .fixed-row-bottom { position: fixed; bottom: 0;} 2 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {OauthAuthorizationService} from "./services/oauth-authorization.service"; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.scss'] 8 | }) 9 | export class AppComponent implements OnInit { 10 | title = 'Client'; 11 | constructor(private auth: OauthAuthorizationService) { 12 | this.auth.CheckAuthentication(); 13 | } 14 | 15 | ngOnInit() { 16 | if (this.auth.IsAuthenticated) { 17 | this.auth.Renew(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/generalchat/generalchat.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{msg}} 5 |
6 |
7 |
8 | 9 | 19 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/generalchat/generalchat.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter06/Client/src/app/components/generalchat/generalchat.component.scss -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/generalchat/generalchat.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { GeneralchatComponent } from './generalchat.component'; 4 | 5 | describe('GeneralchatComponent', () => { 6 | let component: GeneralchatComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ GeneralchatComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(GeneralchatComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/generalchat/generalchat.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnDestroy, OnInit} from '@angular/core'; 2 | import {ChatMessagesService} from "../../services/chat-messages.service"; 3 | import { Subscription } from 'rxjs'; 4 | 5 | @Component({ 6 | selector: 'atp-generalchat', 7 | templateUrl: './generalchat.component.html', 8 | styleUrls: ['./generalchat.component.scss'] 9 | }) 10 | export class GeneralchatComponent implements OnInit, OnDestroy { 11 | 12 | private subscription: Subscription; 13 | messages: string[] = []; 14 | constructor(private chatService: ChatMessagesService) { } 15 | 16 | ngOnInit() { 17 | this.subscription = this.chatService.GetMessages('').subscribe((msg: string) =>{ 18 | this.messages.push(msg); 19 | }); 20 | } 21 | 22 | ngOnDestroy() { 23 | if (this.subscription) { 24 | this.subscription.unsubscribe(); 25 | } 26 | } 27 | CurrentMessage: string; 28 | 29 | SendMessage(): void { 30 | this.chatService.SendMessage(this.CurrentMessage); 31 | this.CurrentMessage = ''; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/navigation/navigation.component.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/navigation/navigation.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter06/Client/src/app/components/navigation/navigation.component.scss -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/navigation/navigation.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavigationComponent } from './navigation.component'; 4 | 5 | describe('NavigationComponent', () => { 6 | let component: NavigationComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NavigationComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NavigationComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/navigation/navigation.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {OauthAuthorizationService} from "../../services/oauth-authorization.service"; 3 | 4 | @Component({ 5 | selector: 'atp-navigation', 6 | templateUrl: './navigation.component.html', 7 | styleUrls: ['./navigation.component.scss'] 8 | }) 9 | export class NavigationComponent implements OnInit { 10 | 11 | constructor(private auth: OauthAuthorizationService) { 12 | } 13 | 14 | ngOnInit() { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/secretchat/secretchat.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{msg}} 5 |
6 |
7 |
8 | 9 |
10 | 20 |
21 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/secretchat/secretchat.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter06/Client/src/app/components/secretchat/secretchat.component.scss -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/secretchat/secretchat.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SecretchatComponent } from './secretchat.component'; 4 | 5 | describe('SecretchatComponent', () => { 6 | let component: SecretchatComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SecretchatComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SecretchatComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/components/secretchat/secretchat.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnDestroy, OnInit} from '@angular/core'; 2 | import {ChatMessagesService} from "../../services/chat-messages.service"; 3 | import {Subscription} from "rxjs"; 4 | 5 | @Component({ 6 | selector: 'atp-secretchat', 7 | templateUrl: './secretchat.component.html', 8 | styleUrls: ['./secretchat.component.scss'] 9 | }) 10 | export class SecretchatComponent implements OnInit, OnDestroy { 11 | 12 | private subscription: Subscription; 13 | 14 | messages: string[] = []; 15 | 16 | constructor(private chatService: ChatMessagesService) { 17 | } 18 | 19 | ngOnInit() { 20 | this.messages = []; 21 | this.subscription = this.chatService.GetMessages('secret').subscribe((msg: string) =>{ 22 | this.messages.push(msg) 23 | }); 24 | } 25 | 26 | ngOnDestroy() { 27 | if (this.subscription) { 28 | this.subscription.unsubscribe(); 29 | } 30 | } 31 | 32 | CurrentMessage: string; 33 | 34 | SendMessage(): void { 35 | this.chatService.SendMessage(this.CurrentMessage); 36 | this.CurrentMessage = ''; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/services/authorization.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AuthorizationService } from './authorization.service'; 4 | 5 | describe('AuthorizationService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: AuthorizationService = TestBed.get(AuthorizationService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/services/authorization.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from "@angular/router"; 3 | import {OauthAuthorizationService} from "./oauth-authorization.service"; 4 | import {Observable} from "rxjs"; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AuthorizationService implements CanActivate { 10 | 11 | constructor(private router: Router, private authorization: OauthAuthorizationService) { } 12 | 13 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): 14 | Observable | Promise | boolean | UrlTree { 15 | if (!this.authorization.IsAuthenticated) { 16 | this.router.navigate(['general']); 17 | return false; 18 | } 19 | return true; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/services/authorization.ts: -------------------------------------------------------------------------------- 1 | import {Socket} from "ngx-socket-io"; 2 | import {Log} from "../Types/Logging"; 3 | 4 | export class Authorization { 5 | 6 | constructor(private socket: Socket) {} 7 | public IdToken: string; 8 | public AccessToken: string; 9 | public Expired: number; 10 | public Email: string; 11 | 12 | @Log() 13 | public Clear(): void { 14 | this.socket.emit('loggedOff', this.Email); 15 | this.IdToken = ''; 16 | this.AccessToken = ''; 17 | this.Expired = 0; 18 | this.Email = ''; 19 | } 20 | 21 | @Log() 22 | public SetFromAuthorizationResult(authResult: any): void { 23 | if (authResult && authResult.accessToken && authResult.idToken) { 24 | this.IdToken = authResult.idToken; 25 | this.AccessToken = authResult.accessToken; 26 | this.Expired = (authResult.expiresIn * 1000) + Date.now(); 27 | this.Email = authResult.idTokenPayload.email; 28 | this.socket.emit('loggedOn', this.Email); 29 | } 30 | } 31 | 32 | public get IsAuthenticated(): boolean { 33 | return this.AccessToken && this.Expired > Date.now(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/services/chat-messages.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ChatMessagesService } from './chat-messages.service'; 4 | 5 | describe('ChatMessagesService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ChatMessagesService = TestBed.get(ChatMessagesService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/services/chat-messages.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {Socket} from "ngx-socket-io"; 3 | import {Observable} from "rxjs"; 4 | import {UserLogon} from "../Types/user.logon"; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class ChatMessagesService { 10 | 11 | constructor(private socket: Socket) { } 12 | 13 | private JoinRoom = (room: string) => { 14 | this.socket.emit('joinRoom', room); 15 | }; 16 | 17 | public SendMessage = (message: string) => { 18 | this.socket.emit('message', message); 19 | }; 20 | 21 | public GetMessages = (room: string) => { 22 | this.JoinRoom(room); 23 | return Observable.create((ob) => { 24 | this.socket.fromEvent('userLogOn').subscribe((user:UserLogon) => { 25 | ob.next(`${user.user} logged on at ${user.time}`); 26 | }); 27 | this.socket.on('message', (msg:string) => { 28 | ob.next(msg); 29 | }); 30 | this.socket.on('allMessages', (msg:string[]) => { 31 | msg.forEach((text:any) => ob.next(text.messageText)); 32 | }); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Chapter06/Client/src/app/services/oauth-authorization.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { OauthAuthorizationService } from './oauth-authorization.service'; 4 | 5 | describe('OauthAuthorizationService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: OauthAuthorizationService = TestBed.get(OauthAuthorizationService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter06/Client/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter06/Client/src/assets/.gitkeep -------------------------------------------------------------------------------- /Chapter06/Client/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /Chapter06/Client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /Chapter06/Client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /Chapter06/Client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter06/Client/src/favicon.ico -------------------------------------------------------------------------------- /Chapter06/Client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Advanced TypeScript 3 Projects - Chatroom 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Chapter06/Client/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage/Client'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /Chapter06/Client/src/main.ts: -------------------------------------------------------------------------------- 1 | import 'hammerjs'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | import { environment } from './environments/environment'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /Chapter06/Client/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | -------------------------------------------------------------------------------- /Chapter06/Client/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /Chapter06/Client/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Chapter06/Client/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Chapter06/Client/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "atp", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "atp", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter06/Client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter06/Server/.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /node_modules 3 | ../.idea -------------------------------------------------------------------------------- /Chapter06/Server/Database/DataAccess/DataAccessBase.ts: -------------------------------------------------------------------------------- 1 | import * as mongoose from "mongoose"; 2 | import {Model} from "../Types"; 3 | 4 | export abstract class DataAccessBase{ 5 | private model: Model; 6 | protected constructor(model: Model) { 7 | this.model = model; 8 | } 9 | Add(item: T): Promise { 10 | return new Promise((callback, error) => { 11 | this.model.create(item, (err: unknown, result: T) => { 12 | if (err) { 13 | error(err); 14 | } 15 | callback(!result); 16 | }); 17 | }); 18 | } 19 | 20 | GetAll(conditions: unknown, fields: unknown): Promise { 21 | return new Promise((callback, error) => { 22 | this.model.find(conditions, fields, (err: unknown, result: T[]) => { 23 | if (err) { 24 | error(err); 25 | } 26 | if (result) { 27 | callback(result); 28 | } 29 | }); 30 | }); 31 | } 32 | } -------------------------------------------------------------------------------- /Chapter06/Server/Database/DataAccess/Messages.ts: -------------------------------------------------------------------------------- 1 | import mongoose, {Schema} from "mongoose"; 2 | import {DataAccessBase} from "./DataAccessBase"; 3 | 4 | export interface IMessageSchema extends mongoose.Document{ 5 | room: string; 6 | messageText: string; 7 | received: Date; 8 | } 9 | 10 | export const MessageSchema = new Schema({ 11 | room: String, 12 | messageText: String, 13 | received: Date 14 | }); 15 | 16 | export const MessageModel = mongoose.model('message', MessageSchema, 'messages', false); 17 | 18 | export class MessageDataAccess extends DataAccessBase { 19 | constructor() { 20 | super(MessageModel); 21 | } 22 | } -------------------------------------------------------------------------------- /Chapter06/Server/Database/Database.ts: -------------------------------------------------------------------------------- 1 | import mongoose, {mongo, Schema} from "mongoose"; 2 | 3 | export function Mongo(connection: string) { 4 | return function (constructor: Function) { 5 | mongoose.connect(connection, { useNewUrlParser: true}, (e:unknown) => { 6 | if (e) { 7 | console.log(`Unable to connect ` + e); 8 | } else { 9 | console.log(`Connected to the database`); 10 | } 11 | }); 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter06/Server/Database/Types.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | export type Model = mongoose.Model 4 | 5 | export const SecuredDatabase = { 6 | connection: 'mongodb://localhost:27017/packt_atp_chapter_06' 7 | }; -------------------------------------------------------------------------------- /Chapter06/Server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "socket-io-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./dist/server.js", 6 | "scripts": { 7 | "start": "nodemon ./dist/server.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/bcrypt-nodejs": "0.0.30", 14 | "@types/bluebird": "^3.5.26", 15 | "@types/body-parser": "^1.17.0", 16 | "@types/cors": "^2.8.4", 17 | "@types/express": "^4.16.1", 18 | "@types/jsonwebtoken": "^8.3.2", 19 | "@types/mongoose": "^5.3.24", 20 | "@types/passport": "^1.0.0", 21 | "@types/passport-jwt": "^3.0.1", 22 | "@types/socket.io": "^2.1.2", 23 | "bcrypt-nodejs": "0.0.3", 24 | "bluebird": "^3.5.3", 25 | "body-parser": "^1.18.3", 26 | "cors": "^2.8.5", 27 | "express": "^4.16.4", 28 | "jsonwebtoken": "^8.5.1", 29 | "mongoose": "^5.4.20", 30 | "morgan": "^1.9.1", 31 | "nodemon": "^1.18.10", 32 | "passport": "^0.4.0", 33 | "passport-jwt": "^4.0.0", 34 | "serve-favicon": "^2.5.0", 35 | "socket.io": "^2.2.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Chapter07/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /Chapter07/README.md: -------------------------------------------------------------------------------- 1 | # About the Firebase settings 2 | 3 | While I have provided a set of default values in environment.ts, this is a placeholder only because this referred to settings I used when I set up the application. You need to follow the instructions to sign up to Firebase. 4 | 5 | Note, if you cannot save to the database - open the Browser debug console window - if this is telling you that you have a Firebase permission exception, it means that you have signed up in locked mode and not test mode. Fixing this is simple enough - all you need to do is open up the Firebase Console and select Database > Rules. Make sure they match this: 6 | 7 | rules_version = '2'; 8 | service cloud.firestore { 9 | match /databases/{database}/documents { 10 | match /{document=**} { 11 | allow read, write: if true; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter07/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Chapter07/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Component } from '@angular/core'; 3 | 4 | @Component({ 5 | selector: 'atp-root', 6 | templateUrl: './app.component.html', 7 | styles: [] 8 | }) 9 | export class AppComponent { 10 | title = 'Mapper'; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter07/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { MapViewComponent } from './components/map-view/map-view.component'; 6 | import { MappingcontainerComponent } from './components/mappingcontainer/mappingcontainer.component'; 7 | import { AngularFireModule } from '@angular/fire'; 8 | import { AngularFirestoreModule } from '@angular/fire/firestore'; 9 | import { AngularFireStorageModule } from '@angular/fire/storage'; 10 | import { environment } from '../environments/environment'; 11 | import { HttpClientModule } from '@angular/common/http'; 12 | 13 | @NgModule({ 14 | declarations: [ 15 | AppComponent, 16 | MapViewComponent, 17 | MappingcontainerComponent 18 | ], 19 | imports: [ 20 | BrowserModule, 21 | HttpClientModule, 22 | AngularFireModule.initializeApp(environment.firebase), 23 | AngularFireStorageModule, 24 | AngularFirestoreModule 25 | ], 26 | providers: [], 27 | bootstrap: [AppComponent] 28 | }) 29 | export class AppModule { } 30 | -------------------------------------------------------------------------------- /Chapter07/src/app/components/map-view/map-view.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | -------------------------------------------------------------------------------- /Chapter07/src/app/components/map-view/map-view.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter07/src/app/components/map-view/map-view.component.scss -------------------------------------------------------------------------------- /Chapter07/src/app/components/map-view/map-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MapViewComponent } from './map-view.component'; 4 | 5 | describe('MapViewComponent', () => { 6 | let component: MapViewComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MapViewComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MapViewComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter07/src/app/components/map-view/map-view.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import {Component, EventEmitter, OnInit, Output, ViewChild} from '@angular/core'; 4 | import {environment} from 'src/environments/environment.prod'; 5 | 6 | @Component({ 7 | selector: 'atp-map-view', 8 | templateUrl: './map-view.component.html', 9 | styleUrls: ['./map-view.component.scss'], 10 | host: { 11 | '(window:load)' : 'Loaded()' 12 | } 13 | }) 14 | export class MapViewComponent implements OnInit { 15 | @ViewChild('myMap') myMap: { nativeElement: string | HTMLElement; }; 16 | 17 | constructor() { } 18 | 19 | ngOnInit() { 20 | 21 | } 22 | 23 | @Output() map = new EventEmitter(); 24 | 25 | Loaded() { 26 | // Bing has a nasty habit of not working properly in browsers like Chrome if we don't hook the map up 27 | // in the window.load event. 28 | const map = new Microsoft.Maps.Map(this.myMap.nativeElement, { 29 | credentials: environment.mapKey, 30 | enableCORS: true, 31 | zoom: 13, mapTypeId:Microsoft.Maps.MapTypeId.road 32 | }); 33 | 34 | this.map.emit(map); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Chapter07/src/app/components/mappingcontainer/mappingcontainer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
-------------------------------------------------------------------------------- /Chapter07/src/app/components/mappingcontainer/mappingcontainer.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter07/src/app/components/mappingcontainer/mappingcontainer.component.scss -------------------------------------------------------------------------------- /Chapter07/src/app/components/mappingcontainer/mappingcontainer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MappingcontainerComponent } from './mappingcontainer.component'; 4 | 5 | describe('MappingcontainerComponent', () => { 6 | let component: MappingcontainerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MappingcontainerComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MappingcontainerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /Chapter07/src/app/components/mappingcontainer/mappingcontainer.component.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { Component, OnInit } from '@angular/core'; 4 | import { MapEvents } from '../../general/MapEvents'; 5 | import { PinsModel } from '../../general/PinsModel'; 6 | import { FirebaseMapPinsService } from 'src/app/services/firebase-map-pins.service'; 7 | import { PointsOfInterestService } from 'src/app/services/points-of-interest.service'; 8 | 9 | @Component({ 10 | selector: 'atp-mappingcontainer', 11 | templateUrl: './mappingcontainer.component.html', 12 | styleUrls: ['./mappingcontainer.component.scss'] 13 | }) 14 | export class MappingcontainerComponent implements OnInit { 15 | 16 | private map: Microsoft.Maps.Map; 17 | private mapEvents: MapEvents; 18 | constructor(private readonly firebaseMapPinService: FirebaseMapPinsService, private poi: PointsOfInterestService) { } 19 | 20 | ngOnInit() { 21 | } 22 | 23 | MapLoaded(map: Microsoft.Maps.Map) { 24 | this.map = map; 25 | this.mapEvents = new MapEvents(this.map, new PinsModel(this.firebaseMapPinService), this.poi); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Chapter07/src/app/general/MapGeocode.ts: -------------------------------------------------------------------------------- 1 | export class MapGeocode { 2 | private searchManager: Microsoft.Maps.Search.SearchManager; 3 | constructor(private map: Microsoft.Maps.Map) { 4 | Microsoft.Maps.loadModule('Microsoft.Maps.Search', () => { 5 | this.searchManager = new Microsoft.Maps.Search.SearchManager(this.map); 6 | }); 7 | } 8 | public ReverseGeocode(location: Microsoft.Maps.Location): Promise { 9 | return new Promise((callback) => { 10 | const request = { 11 | location: location, 12 | callback: function (code) { callback(code.name); } 13 | }; 14 | if (this.searchManager) { 15 | this.searchManager.reverseGeocode(request); 16 | } 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter07/src/app/general/PinModel.ts: -------------------------------------------------------------------------------- 1 | export class PinModel { 2 | id: string; 3 | lat: number; 4 | long: number; 5 | name: string; 6 | } 7 | 8 | export interface PinModelData extends PinModel { 9 | storageId: string; 10 | } -------------------------------------------------------------------------------- /Chapter07/src/app/services/firebase-map-pins.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { FirebaseMapPinsService } from './firebase-map-pins.service'; 4 | 5 | describe('FirebaseMapPinsService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: FirebaseMapPinsService = TestBed.get(FirebaseMapPinsService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter07/src/app/services/firebase-map-pins.service.ts: -------------------------------------------------------------------------------- 1 | import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { PinModel, PinModelData } from '../general/PinModel'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class FirebaseMapPinsService { 10 | 11 | private pins: AngularFirestoreCollection; 12 | public model: Observable 13 | constructor(private readonly db: AngularFirestore) { 14 | this.pins = db.collection('pins'); 15 | this.model = this.pins.valueChanges(); 16 | } 17 | 18 | Save(item: PinModelData) { 19 | if (item.storageId === '') { 20 | item.storageId = this.db.createId(); 21 | this.pins.doc(item.storageId).set(item); 22 | } 23 | else { 24 | this.pins.doc(item.storageId).update(item); 25 | } 26 | } 27 | 28 | Delete(item: PinModelData) { 29 | this.pins.doc(item.storageId).delete(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Chapter07/src/app/services/points-of-interest.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PointsOfInterestService } from './points-of-interest.service'; 4 | 5 | describe('PointsOfInterestService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: PointsOfInterestService = TestBed.get(PointsOfInterestService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter07/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter07/src/assets/.gitkeep -------------------------------------------------------------------------------- /Chapter07/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /Chapter07/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | firebase: { 4 | apiKey: "AIzaSyC0MzFxTtvt6cCvmTGE94xc5INFRYlXznw", 5 | authDomain: "advancedtypescript3-chatapp.firebaseapp.com", 6 | databaseURL: "https://advancedtypescript3-chatapp.firebaseio.com", 7 | projectId: "advancedtypescript3-chatapp", 8 | storageBucket: "advancedtypescript3-chatapp.appspot.com", 9 | messagingSenderId: "6102469443" 10 | }, 11 | mapKey: 'ApKBOGD6mTjyn0tcEXMozQwWz1m7hI6kl2mh74SWyPuzsfyQtc2_pUwYtshoBC1b' 12 | }; 13 | -------------------------------------------------------------------------------- /Chapter07/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter07/src/favicon.ico -------------------------------------------------------------------------------- /Chapter07/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /Chapter07/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | html,body { 3 | height: 100%; 4 | } -------------------------------------------------------------------------------- /Chapter07/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Chapter07/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/Services/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | Dockerfile* 4 | docker-compose* 5 | .dockerignore 6 | .git 7 | .gitignore 8 | .env 9 | */bin 10 | */obj 11 | README.md 12 | LICENSE 13 | .vscode -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package*.json ./ 6 | 7 | RUN npm install 8 | 9 | COPY . . 10 | 11 | EXPOSE 3000 12 | 13 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/Routing/GetAddressRouting.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "../../Common/Routing/Router"; 2 | import { AddressesService } from "../api/Models/AddressesService"; 3 | import { Request, Response } from "express"; 4 | 5 | export class GetAddressRouting implements IRouter { 6 | AddRoute(route: any): void { 7 | route.get('/get/', async (request: Request, response: Response) => { 8 | const result = await new AddressesService().GetAll(); 9 | if (result) { 10 | response.json(result); 11 | } 12 | response.send(''); 13 | }); 14 | } 15 | } -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/Routing/SaveAddressRouting.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "../../Common/Routing/Router"; 2 | import { Request, Response } from "express"; 3 | import { IAddress } from "../api/Models/Addresses"; 4 | import { AddressesService } from "../api/Models/AddressesService"; 5 | export class SaveAddressRouting implements IRouter { 6 | AddRoute(route: any): void { 7 | route.post('/add/', (request: Request, response: Response) => { 8 | const person: IAddress = {...request.body}; 9 | new AddressesService().Save(person); 10 | response.json(person); 11 | }); 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/api/Models/Addresses.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseModelBase } from "../../../Common/Model/DatabaseModelBase"; 2 | 3 | export interface IAddress extends IDatabaseModelBase { 4 | Line1 : string, 5 | Line2 : string, 6 | Line3 : string, 7 | Line4 : string, 8 | PostalCode : string 9 | } -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/api/Models/AddressesService.ts: -------------------------------------------------------------------------------- 1 | import { IAddress } from './Addresses'; 2 | import { FirestoreService } from '../../../Common/Model/FirestoreService'; 3 | 4 | export class AddressesService extends FirestoreService { 5 | constructor() { 6 | super('addresses'); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/build.cmd: -------------------------------------------------------------------------------- 1 | docker build -t ohanlon/addresses . 2 | docker run -p 17171:3000 -d ohanlon/addresses -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "addresses", 3 | "version": "1.0.0", 4 | "description": "Dockerized addresses service", 5 | "main": "./dist/Addresses/service.js", 6 | "scripts": { 7 | "start": "nodemon", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/cors": "^2.8.5", 14 | "@types/express": "^4.16.1", 15 | "@types/firebase": "^3.2.1", 16 | "cors": "^2.8.5", 17 | "express": "^4.16.4", 18 | "firebase": "^5.10.0", 19 | "guid-typescript": "^1.0.9", 20 | "nodemon": "^1.18.11" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/service.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { Server } from "../Common/Server"; 3 | import { SaveAddressRouting } from "./Routing/SaveAddressRouting"; 4 | import { GetAddressRouting } from "./Routing/GetAddressRouting"; 5 | 6 | export class AddressesServer extends Server { 7 | protected AddRouting(router: Router): void { 8 | this.routingEngine.Add(GetAddressRouting, router); 9 | this.routingEngine.Add(SaveAddressRouting, router); 10 | } 11 | } 12 | 13 | new AddressesServer() 14 | .WithCorsSupport() 15 | .WithDatabase().Start(); -------------------------------------------------------------------------------- /Chapter08/Services/Addresses/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compileOnSave": true, 4 | "compilerOptions": { 5 | "outDir": "./dist", 6 | } 7 | } -------------------------------------------------------------------------------- /Chapter08/Services/Common/.gitignore: -------------------------------------------------------------------------------- 1 | // Exclude our server environment 2 | Configuration/Environment.ts -------------------------------------------------------------------------------- /Chapter08/Services/Common/Model/DatabaseModelBase.ts: -------------------------------------------------------------------------------- 1 | export interface IDatabaseModelBase { 2 | ServerID: string; 3 | } -------------------------------------------------------------------------------- /Chapter08/Services/Common/Routing/Router.ts: -------------------------------------------------------------------------------- 1 | export interface IRouter { 2 | AddRoute(route: any): void; 3 | } 4 | -------------------------------------------------------------------------------- /Chapter08/Services/Common/Routing/RoutingEngine.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "./Router"; 2 | export class RoutingEngine { 3 | constructor(private routing: IRouter[] = new Array()) { 4 | } 5 | public Add(routing: (new () => T1), route: any) { 6 | const routed = new routing(); 7 | routed.AddRoute(route); 8 | this.routing.push(routed); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter08/Services/Common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "people", 3 | "version": "1.0.0", 4 | "description": "Dockerized people service", 5 | "main": "./dist/People/server.js", 6 | "scripts": { 7 | "start": "nodemon", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/cors": "^2.8.5", 14 | "@types/express": "^4.16.1", 15 | "@types/firebase": "^3.2.1", 16 | "cors": "^2.8.5", 17 | "express": "^4.16.4", 18 | "firebase": "^5.10.0", 19 | "guid-typescript": "^1.0.9", 20 | "nodemon": "^1.18.11" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/Services/Leads/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /Chapter08/Services/Leads/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package*.json ./ 6 | 7 | RUN npm install 8 | 9 | COPY . . 10 | 11 | EXPOSE 3000 12 | 13 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Chapter08/Services/Leads/Routing/GetLeadsRouting.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "../../Common/Routing/Router"; 2 | import { LeadsService } from "../api/Models/LeadService"; 3 | import { Request, Response } from "express"; 4 | 5 | export class GetLeadsRouting implements IRouter { 6 | AddRoute(route: any): void { 7 | route.get('/get/', async (request: Request, response: Response) => { 8 | const result = await new LeadsService().GetAll(); 9 | if (result) { 10 | response.json(result); 11 | } 12 | response.send(''); 13 | }); 14 | } 15 | } -------------------------------------------------------------------------------- /Chapter08/Services/Leads/Routing/SaveLeadsRouting.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "../../Common/Routing/Router"; 2 | import { Request, Response } from "express"; 3 | import { ILead } from "../api/Models/Lead"; 4 | import { LeadsService } from "../api/Models/LeadService"; 5 | export class SaveLeadsRouting implements IRouter { 6 | AddRoute(route: any): void { 7 | route.post('/add/', (request: Request, response: Response) => { 8 | const person: ILead = {...request.body}; 9 | new LeadsService().Save(person); 10 | response.json(person); 11 | }); 12 | } 13 | } -------------------------------------------------------------------------------- /Chapter08/Services/Leads/api/Models/Lead.ts: -------------------------------------------------------------------------------- 1 | import { IDatabaseModelBase } from "../../../Common/Model/DatabaseModelBase"; 2 | 3 | export interface ILead extends IDatabaseModelBase { 4 | Name: string; 5 | Topic: string; 6 | Created: Date; 7 | Status: string; 8 | } -------------------------------------------------------------------------------- /Chapter08/Services/Leads/api/Models/LeadService.ts: -------------------------------------------------------------------------------- 1 | import { ILead } from './Lead'; 2 | import { FirestoreService } from '../../../Common/Model/FirestoreService'; 3 | 4 | export class LeadsService extends FirestoreService { 5 | constructor() { 6 | super('leads'); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Chapter08/Services/Leads/build.cmd: -------------------------------------------------------------------------------- 1 | docker build -t ohanlon/leads . 2 | docker run -p 65432:3000 -d ohanlon/leads -------------------------------------------------------------------------------- /Chapter08/Services/Leads/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leads", 3 | "version": "1.0.0", 4 | "description": "Dockerized leads service", 5 | "main": "./dist/Leads/service.js", 6 | "scripts": { 7 | "start": "nodemon", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/cors": "^2.8.5", 14 | "@types/express": "^4.16.1", 15 | "@types/firebase": "^3.2.1", 16 | "cors": "^2.8.5", 17 | "express": "^4.16.4", 18 | "firebase": "^5.10.0", 19 | "guid-typescript": "^1.0.9", 20 | "nodemon": "^1.18.11" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/Services/Leads/service.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { Server } from "../Common/Server"; 3 | import { GetLeadsRouting } from "./Routing/GetLeadsRouting"; 4 | import { SaveLeadsRouting } from "./Routing/SaveLeadsRouting"; 5 | 6 | export class LeadsServer extends Server { 7 | protected AddRouting(router: Router): void { 8 | this.routingEngine.Add(GetLeadsRouting, router); 9 | this.routingEngine.Add(SaveLeadsRouting, router); 10 | } 11 | } 12 | 13 | new LeadsServer() 14 | .WithCorsSupport() 15 | .WithDatabase().Start(); -------------------------------------------------------------------------------- /Chapter08/Services/Leads/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compileOnSave": true, 4 | "compilerOptions": { 5 | "outDir": "./dist", 6 | } 7 | } -------------------------------------------------------------------------------- /Chapter08/Services/People/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log -------------------------------------------------------------------------------- /Chapter08/Services/People/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package*.json ./ 6 | 7 | RUN npm install 8 | 9 | COPY . . 10 | 11 | EXPOSE 3000 12 | 13 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /Chapter08/Services/People/Routing/GetPeopleRouting.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "../../Common/Routing/Router"; 2 | import { PersonService } from "../api/Models/PersonService"; 3 | import { Request, Response } from "express"; 4 | 5 | export class GetPeopleRouting implements IRouter { 6 | AddRoute(route: any): void { 7 | route.get('/get/', async (request: Request, response: Response) => { 8 | const result = await new PersonService().GetAll(); 9 | if (result) { 10 | response.json(result); 11 | } 12 | response.send(''); 13 | }); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter08/Services/People/Routing/SavePeopleRouting.ts: -------------------------------------------------------------------------------- 1 | import { IRouter } from "../../Common/Routing/Router"; 2 | import { Request, Response } from "express"; 3 | import { IPerson } from "../api/Models/People"; 4 | import { PersonService } from "../api/Models/PersonService"; 5 | export class SavePeopleRouting implements IRouter { 6 | AddRoute(route: any): void { 7 | route.post('/add/', (request: Request, response: Response) => { 8 | const person: IPerson = {...request.body}; 9 | new PersonService().Save(person); 10 | response.json(person); 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter08/Services/People/api/Models/People.ts: -------------------------------------------------------------------------------- 1 | import { IAddress } from "../../../Addresses/api/Models/Addresses"; 2 | import { IDatabaseModelBase } from "../../../Common/Model/DatabaseModelBase"; 3 | 4 | export interface IPerson extends IDatabaseModelBase { 5 | FirstName: string; 6 | LastName: string; 7 | Address: IAddress; 8 | } -------------------------------------------------------------------------------- /Chapter08/Services/People/api/Models/PersonService.ts: -------------------------------------------------------------------------------- 1 | import { IPerson } from './People'; 2 | import { FirestoreService } from '../../../Common/Model/FirestoreService'; 3 | 4 | export class PersonService extends FirestoreService { 5 | constructor() { 6 | super('people'); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Chapter08/Services/People/build.cmd: -------------------------------------------------------------------------------- 1 | docker build -t ohanlon/people . 2 | docker run -p 31313:3000 -d ohanlon/people -------------------------------------------------------------------------------- /Chapter08/Services/People/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "people", 3 | "version": "1.0.0", 4 | "description": "Dockerized people service", 5 | "main": "./dist/People/server.js", 6 | "scripts": { 7 | "start": "nodemon", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/cors": "^2.8.5", 14 | "@types/express": "^4.16.1", 15 | "@types/firebase": "^3.2.1", 16 | "cors": "^2.8.5", 17 | "express": "^4.16.4", 18 | "firebase": "^5.10.0", 19 | "guid-typescript": "^1.0.9", 20 | "nodemon": "^1.18.11" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Chapter08/Services/People/server.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { Server } from "../Common/Server"; 3 | import { GetPeopleRouting } from "./Routing/GetPeopleRouting"; 4 | import { SavePeopleRouting } from "./Routing/SavePeopleRouting"; 5 | 6 | export class PeopleServer extends Server { 7 | protected AddRouting(router: Router): void { 8 | this.routingEngine.Add(GetPeopleRouting, router); 9 | this.routingEngine.Add(SavePeopleRouting, router); 10 | } 11 | } 12 | 13 | new PeopleServer() 14 | .WithCorsSupport() 15 | .WithDatabase().Start(); -------------------------------------------------------------------------------- /Chapter08/Services/People/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compileOnSave": true, 4 | "compilerOptions": { 5 | "outDir": "./dist", 6 | } 7 | } -------------------------------------------------------------------------------- /Chapter08/Services/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | services: 4 | chapter08_addresses: 5 | build: 6 | context: ./Addresses 7 | dockerfile: ./Dockerfile 8 | environment: 9 | NODE_ENV: production 10 | ports: 11 | - 17171:3000 12 | chapter08_people: 13 | build: 14 | context: ./People 15 | dockerfile: ./Dockerfile 16 | environment: 17 | NODE_ENV: production 18 | ports: 19 | - 31313:3000 20 | chapter08_leads: 21 | build: 22 | context: ./Leads 23 | dockerfile: ./Dockerfile 24 | environment: 25 | NODE_ENV: production 26 | ports: 27 | - 65432:3000 28 | -------------------------------------------------------------------------------- /Chapter08/Services/runall.cmd: -------------------------------------------------------------------------------- 1 | FOR /f "tokens=*" %%i IN ('docker ps -q') DO docker stop %%i 2 | CD People 3 | CALL build.cmd 4 | CD ..\Leads 5 | CALL build.cmd 6 | CD ..\Addresses 7 | CALL build.cmd 8 | -------------------------------------------------------------------------------- /Chapter08/Services/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "es5", 5 | "module": "commonjs", 6 | "removeComments": true, 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "inlineSourceMap": true, 10 | "experimentalDecorators": true, 11 | } 12 | } -------------------------------------------------------------------------------- /Chapter08/SwaggerAPI/typescript-node-client-generated/.gitignore: -------------------------------------------------------------------------------- 1 | wwwroot/*.js 2 | node_modules 3 | typings 4 | -------------------------------------------------------------------------------- /Chapter08/SwaggerAPI/typescript-node-client-generated/.swagger-codegen-ignore: -------------------------------------------------------------------------------- 1 | # Swagger Codegen Ignore 2 | # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /Chapter08/SwaggerAPI/typescript-node-client-generated/.swagger-codegen/VERSION: -------------------------------------------------------------------------------- 1 | 2.4.5 -------------------------------------------------------------------------------- /Chapter08/crmclient/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /Chapter08/crmclient/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' 2 | declare module '*.png' 3 | declare module '*.jpg' 4 | declare module '*.jpeg' 5 | declare module '*.gif' 6 | declare module '*.bmp' 7 | declare module '*.tiff' 8 | -------------------------------------------------------------------------------- /Chapter08/crmclient/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crmclient", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/react-router-dom": "^4.3.2", 7 | "@types/react-select": "^2.0.17", 8 | "@types/react-table": "^6.8.1", 9 | "axios": "^0.18.0", 10 | "bootstrap": "^4.3.1", 11 | "react": "^16.8.6", 12 | "react-bootstrap": "^1.0.0-beta.8", 13 | "react-dom": "^16.8.6", 14 | "react-router-dom": "^5.0.0", 15 | "react-scripts-ts": "3.1.0", 16 | "react-select": "^2.4.3", 17 | "react-table": "^6.10.0" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts-ts start", 21 | "build": "react-scripts-ts build", 22 | "test": "react-scripts-ts test --env=jsdom", 23 | "eject": "react-scripts-ts eject" 24 | }, 25 | "devDependencies": { 26 | "@types/jest": "^24.0.12", 27 | "@types/node": "^11.13.8", 28 | "@types/react": "^16.8.15", 29 | "@types/react-dom": "^16.8.4", 30 | "typescript": "^3.4.5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter08/crmclient/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter08/crmclient/public/favicon.ico -------------------------------------------------------------------------------- /Chapter08/crmclient/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /Chapter08/crmclient/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-title { 18 | font-size: 1.5em; 19 | } 20 | 21 | .App-intro { 22 | font-size: large; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { transform: rotate(0deg); } 27 | to { transform: rotate(360deg); } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter08/crmclient/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /Chapter08/crmclient/src/App.tsx: -------------------------------------------------------------------------------- 1 | // import axios from "axios"; 2 | import * as React from 'react'; 3 | import { Container } from "react-bootstrap"; 4 | import './App.css'; 5 | 6 | export class App extends React.Component { 7 | public render() { 8 | return ( 9 | 10 |
11 | 12 | ); 13 | } 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /Chapter08/crmclient/src/components/StatusChoice.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Form } from "react-bootstrap"; 3 | export interface IStatusProperty { 4 | CurrentSelection : (currentSelection:string) => void; 5 | } 6 | export class StatusChoice extends React.Component { 7 | constructor(prop: any) { 8 | super(prop); 9 | this.Changed = this.Changed.bind(this); 10 | } 11 | public render() { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | } 18 | private Changed(optionSelected: any) { 19 | this.props.CurrentSelection(optionSelected.target.value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chapter08/crmclient/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /Chapter08/crmclient/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "outDir": "build/dist", 5 | "module": "esnext", 6 | "target": "es5", 7 | "lib": ["es6", "dom"], 8 | "sourceMap": true, 9 | "allowJs": true, 10 | "jsx": "react", 11 | "moduleResolution": "node", 12 | "rootDir": "src", 13 | "forceConsistentCasingInFileNames": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "noImplicitAny": true, 17 | "importHelpers": true, 18 | "strictNullChecks": true, 19 | "suppressImplicitAnyIndexErrors": true, 20 | "noUnusedLocals": true 21 | }, 22 | "exclude": [ 23 | "node_modules", 24 | "build", 25 | "scripts", 26 | "acceptance-tests", 27 | "webpack", 28 | "jest", 29 | "src/setupTests.ts" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /Chapter08/crmclient/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } -------------------------------------------------------------------------------- /Chapter08/crmclient/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } -------------------------------------------------------------------------------- /Chapter08/crmclient/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-config-prettier"], 3 | "linterOptions": { 4 | "exclude": [ 5 | "config/**/*.js", 6 | "node_modules/**/*.ts", 7 | "coverage/lcov-report/*.js" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter09/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /Chapter09/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /Chapter09/README.md: -------------------------------------------------------------------------------- 1 | # chapter09 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /Chapter09/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chapter09", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@tensorflow-models/mobilenet": "^1.0.1", 12 | "@tensorflow-models/posenet": "^1.0.2", 13 | "@tensorflow/tfjs": "^1.1.2", 14 | "bootstrap": "^4.3.1", 15 | "bootstrap-vue": "^2.0.0-rc.19", 16 | "vue": "^2.6.10", 17 | "vue-class-component": "^7.0.2", 18 | "vue-property-decorator": "^8.1.0", 19 | "vue-router": "^3.0.3", 20 | "vuex": "^3.0.1" 21 | }, 22 | "devDependencies": { 23 | "@vue/cli-plugin-typescript": "^3.7.0", 24 | "@vue/cli-service": "^3.7.0", 25 | "typescript": "^3.4.3", 26 | "vue-template-compiler": "^2.5.21" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter09/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Chapter09/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter09/public/favicon.ico -------------------------------------------------------------------------------- /Chapter09/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Advanced TypeScript - Machine Learning 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Chapter09/src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 29 | -------------------------------------------------------------------------------- /Chapter09/src/Models/DrawPose.ts: -------------------------------------------------------------------------------- 1 | import {Keypoint} from '@tensorflow-models/posenet'; 2 | 3 | export class DrawPose { 4 | constructor(private canvas: HTMLCanvasElement, private context = canvas.getContext('2d')) { 5 | this.context!.clearRect(0, 0, this.canvas.offsetWidth, this.canvas.offsetHeight); 6 | this.context!.fillStyle = '#ff0300'; 7 | } 8 | 9 | public Draw(keys: Keypoint[]): void { 10 | keys.forEach((kp: Keypoint) => { 11 | this.context!.fillRect(kp.position.x - 2.5, kp.position.y - 2.5, 5, 5); 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter09/src/Models/ImageClassifier.ts: -------------------------------------------------------------------------------- 1 | import * as mobilenet from '@tensorflow-models/mobilenet'; 2 | import {MobileNet} from '@tensorflow-models/mobilenet'; 3 | import * as tf from '@tensorflow/tfjs'; 4 | import {TensorInformation} from '@/Models/TensorInformation'; 5 | 6 | export class ImageClassifier { 7 | private model: MobileNet | null = null; 8 | 9 | constructor() { 10 | // If running on Windows, there can be issues loading WebGL textures properly. 11 | // Running the following command solves this. 12 | tf.ENV.set('WEBGL_PACK', false); 13 | } 14 | public async Classify(image: tf.Tensor3D | ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement): 15 | Promise { 16 | if (!this.model) { 17 | this.model = await mobilenet.load(); 18 | } 19 | 20 | if (this.model) { 21 | const result = await this.model.classify(image); 22 | return { 23 | ...result, 24 | }; 25 | } 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter09/src/Models/PoseClassifier.ts: -------------------------------------------------------------------------------- 1 | import * as tf from '@tensorflow/tfjs'; 2 | import * as posenet from '@tensorflow-models/posenet'; 3 | import {Keypoint, Pose, PoseNet} from '@tensorflow-models/posenet'; 4 | import {DrawPose} from '@/Models/DrawPose'; 5 | 6 | export class PoseClassifier { 7 | private model: PoseNet | null = null; 8 | private drawPose: DrawPose | null = null; 9 | constructor() { 10 | // If running on Windows, there can be issues loading WebGL textures properly. 11 | // Running the following command solves this. 12 | tf.ENV.set('WEBGL_PACK', false); 13 | } 14 | 15 | public async Pose(image: HTMLImageElement, canvas: HTMLCanvasElement): Promise { 16 | if (!this.model) { 17 | this.model = await posenet.load(); 18 | this.drawPose = new DrawPose(canvas); 19 | } 20 | 21 | if (this.model) { 22 | const result: Pose = await this.model.estimateSinglePose(image); 23 | if (result) { 24 | this.drawPose!.Draw(result.keypoints); 25 | return result.keypoints; 26 | } 27 | } 28 | return null; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Chapter09/src/Models/TensorInformation.ts: -------------------------------------------------------------------------------- 1 | export interface TensorInformation { 2 | className: string; 3 | probability: number; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter09/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter09/src/assets/logo.png -------------------------------------------------------------------------------- /Chapter09/src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | import BootstrapVue from 'bootstrap-vue'; 6 | 7 | import 'bootstrap/dist/css/bootstrap.css'; 8 | import 'bootstrap-vue/dist/bootstrap-vue.css'; 9 | 10 | Vue.use(BootstrapVue); 11 | 12 | Vue.config.productionTip = false; 13 | 14 | new Vue({ 15 | router, 16 | store, 17 | render: (h) => h(App), 18 | }).$mount('#app'); 19 | -------------------------------------------------------------------------------- /Chapter09/src/router.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Home from './views/Home.vue'; 4 | import Pose from './views/Pose.vue'; 5 | 6 | Vue.use(Router); 7 | 8 | export default new Router({ 9 | mode: 'history', 10 | base: process.env.BASE_URL, 11 | routes: [ 12 | { 13 | path: '/', 14 | name: 'home', 15 | component: Home, 16 | }, 17 | { 18 | path: '/pose', 19 | name: 'Pose', 20 | component: Pose, 21 | }, 22 | { 23 | path: '*', 24 | component: Home, 25 | }, 26 | ], 27 | }); 28 | -------------------------------------------------------------------------------- /Chapter09/src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue'; 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter09/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue'; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /Chapter09/src/store.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | 9 | }, 10 | mutations: { 11 | 12 | }, 13 | actions: { 14 | 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /Chapter09/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /Chapter09/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "skipLibCheck": true, 15 | "types": [ 16 | "webpack-env" 17 | ], 18 | "paths": { 19 | "@/*": [ 20 | "src/*" 21 | ] 22 | }, 23 | "lib": [ 24 | "esnext", 25 | "dom", 26 | "dom.iterable", 27 | "scripthost" 28 | ] 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /Chapter09/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "node_modules/**" 9 | ] 10 | }, 11 | "rules": { 12 | "quotemark": [true, "single"], 13 | "indent": [true, "spaces", 2], 14 | "interface-name": false, 15 | "ordered-imports": false, 16 | "object-literal-sort-keys": false, 17 | "no-consecutive-blank-lines": false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter10/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ -------------------------------------------------------------------------------- /Chapter10/.vs/Chapter10/DesignTimeBuild/.dtbcache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter10/.vs/Chapter10/DesignTimeBuild/.dtbcache -------------------------------------------------------------------------------- /Chapter10/.vs/Chapter10/v16/Server/sqlite3/db.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter10/.vs/Chapter10/v16/Server/sqlite3/db.lock -------------------------------------------------------------------------------- /Chapter10/.vs/Chapter10/v16/Server/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter10/.vs/Chapter10/v16/Server/sqlite3/storage.ide -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/AdvancedTypeScript3Discogs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.1 5 | 3.4 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/Discogs/CommunityInfo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace AdvancedTypeScript3Discogs.Models.Discogs 4 | { 5 | public class CommunityInfo 6 | { 7 | [JsonProperty(PropertyName = "want")] 8 | public int Want { get; set; } 9 | [JsonProperty(PropertyName = "have")] 10 | public int Have { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/Discogs/EntityType.cs: -------------------------------------------------------------------------------- 1 | namespace AdvancedTypeScript3Discogs.Models.Discogs 2 | { 3 | public enum EntityType 4 | { 5 | release, 6 | master, 7 | artist, 8 | label 9 | } 10 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/Discogs/IDiscogsClient.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace AdvancedTypeScript3Discogs.Models.Discogs 4 | { 5 | public interface IDiscogsClient 6 | { 7 | Task GetByArtist(string artist); 8 | } 9 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/Discogs/PaginationResults.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace AdvancedTypeScript3Discogs.Models.Discogs 4 | { 5 | public class PaginationResults 6 | { 7 | [JsonProperty(PropertyName = "per_page")] 8 | public int PerPage { get; set; } 9 | [JsonProperty(PropertyName = "pages")] 10 | public int Pages { get; set; } 11 | [JsonProperty(PropertyName = "page")] 12 | public int Page { get; set; } 13 | [JsonProperty(PropertyName = "items")] 14 | public int Items { get; set; } 15 | [JsonProperty(PropertyName = "urls")] 16 | public Urls Urls { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/Discogs/Results.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace AdvancedTypeScript3Discogs.Models.Discogs 4 | { 5 | public class Results 6 | { 7 | [JsonProperty(PropertyName="pagination")] 8 | public PaginationResults Pagination { get; set; } 9 | [JsonProperty(PropertyName = "results")] 10 | public SearchResult[] ResultsList { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/Discogs/Urls.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace AdvancedTypeScript3Discogs.Models.Discogs 4 | { 5 | public class Urls 6 | { 7 | [JsonProperty(PropertyName ="first")] 8 | public string First { get; set; } 9 | [JsonProperty(PropertyName = "last")] 10 | public string Last { get; set; } 11 | [JsonProperty(PropertyName = "prev")] 12 | public string Prev { get; set; } 13 | [JsonProperty(PropertyName = "next")] 14 | public string Next { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace AdvancedTypeScript3Discogs.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | 4 | namespace AdvancedTypeScript3Discogs 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateWebHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 14 | WebHost.CreateDefaultBuilder(args) 15 | .UseStartup(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:52541", 7 | "sslPort": 44300 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "AdvancedTypeScript3Discogs": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/TypeScript/discogHelper.ts: -------------------------------------------------------------------------------- 1 | const searchDiscog = (request: RequestInfo, imgId: string): Promise => { 2 | return new Promise((): void => { 3 | fetch(request, 4 | { 5 | method: 'GET', 6 | headers: { 7 | 'authorization': 'Discogs token=MyJEHLsbTIydAXFpGafrrphJhxJWwVhWExCynAQh', 8 | 'user-agent': 'AdvancedTypeScript3Chapter10' 9 | } 10 | }) 11 | .then(response => { 12 | return response.json(); 13 | }) 14 | .then(responseBody => { 15 | // We have an image... Let's use it. 16 | const image = document.getElementById(imgId); 17 | if (image) { 18 | if (responseBody && responseBody.images && responseBody.images.length > 0) { 19 | image.src = responseBody.images["0"].uri150; 20 | } 21 | } 22 | }).catch(x => { 23 | console.log(x); 24 | }); 25 | }); 26 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "About"; 3 | } 4 |

@ViewData["Title"]

5 |

@ViewData["Message"]

6 | 7 |

As well as Node.js, TypeScript can be used very effectively in ASP.NET Core applications. This application introduces us to building applications with ASP.NET Core, Visual Studio and TypeScript.

8 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Contact"; 3 | } 4 |

@ViewData["Title"]

5 |

@ViewData["Message"]

6 | 7 |
8 | Packt Publishing
9 | Livery Place
10 | 35 Livery Street
11 | Birmingham
12 | B3 2PB
13 | P: 14 | 0121 265 6484 15 |
16 | 17 |
18 | Email: hub@packtpub.com
19 |
20 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Privacy Policy"; 3 | } 4 |

@ViewData["Title"]

5 | 6 |

Use this page to detail your site's privacy policy.

7 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | @{ 3 | ViewData["Title"] = "Error"; 4 | } 5 | 6 |

Error.

7 |

An error occurred while processing your request.

8 | 9 | @if (Model.ShowRequestId) 10 | { 11 |

12 | Request ID: @Model.RequestId 13 |

14 | } 15 | 16 |

Development Mode

17 |

18 | Swapping to Development environment will display more detailed information about the error that occurred. 19 |

20 |

21 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 22 |

23 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using AdvancedTypeScript3Discogs 2 | @using AdvancedTypeScript3Discogs.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "AllowedHosts": "*" 8 | } 9 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "lib": [ "es2015", "dom" ], 5 | "noImplicitAny": true, 6 | "noEmitOnError": true, 7 | "removeComments": false, 8 | "sourceMap": true, 9 | "target": "es2015", 10 | "outDir": "wwwroot/js/" 11 | }, 12 | "exclude": [ 13 | "wwwroot" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification\ 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | /* Wrapping element */ 5 | /* Set some basic padding to keep content from hitting the edges */ 6 | .body-content { 7 | padding-left: 15px; 8 | padding-right: 15px; 9 | } 10 | 11 | /* Carousel */ 12 | .carousel-caption p { 13 | font-size: 20px; 14 | line-height: 1.4; 15 | } 16 | 17 | /* Make .svg files in the carousel display properly in older browsers */ 18 | .carousel-inner .item img[src$=".svg"] { 19 | width: 100%; 20 | } 21 | 22 | /* QR code generator */ 23 | #qrCode { 24 | margin: 15px; 25 | } 26 | 27 | /* Hide/rearrange for smaller screens */ 28 | @media screen and (max-width: 767px) { 29 | /* Hide captions */ 30 | .carousel-caption { 31 | display: none; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}} -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter10/AdvancedTypeScript3Discogs/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/js/discogHelper.js: -------------------------------------------------------------------------------- 1 | const searchDiscog = (request, imgId) => { 2 | return new Promise(() => { 3 | fetch(request, { 4 | method: 'GET', 5 | headers: { 6 | 'authorization': 'Discogs token=MyJEHLsbTIydAXFpGafrrphJhxJWwVhWExCynAQh', 7 | 'user-agent': 'AdvancedTypeScript3Chapter10' 8 | } 9 | }) 10 | .then(response => { 11 | return response.json(); 12 | }) 13 | .then(responseBody => { 14 | // We have an image... Let's use it. 15 | const image = document.getElementById(imgId); 16 | if (image) { 17 | if (responseBody && responseBody.images && responseBody.images.length > 0) { 18 | image.src = responseBody.images["0"].uri150; 19 | } 20 | } 21 | }).catch(x => { 22 | console.log(x); 23 | }); 24 | }); 25 | }; 26 | //# sourceMappingURL=discogHelper.js.map -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/js/discogHelper.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"discogHelper.js","sourceRoot":"","sources":["../../TypeScript/discogHelper.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,CAAC,OAAoB,EAAE,KAAa,EAAiB,EAAE;IAC1E,OAAO,IAAI,OAAO,CAAC,GAAS,EAAE;QAC5B,KAAK,CAAC,OAAO,EACX;YACE,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,eAAe,EAAE,wDAAwD;gBACzE,YAAY,EAAE,8BAA8B;aAC7C;SACF,CAAC;aACD,IAAI,CAAC,QAAQ,CAAC,EAAE;YACf,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;QACzB,CAAC,CAAC;aACD,IAAI,CAAC,YAAY,CAAC,EAAE;YACnB,oCAAoC;YACpC,MAAM,KAAK,GAAqB,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC/D,IAAI,KAAK,EAAE;gBACT,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;oBACzE,KAAK,CAAC,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;iBAC7C;aACF;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YACX,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC,CAAA"} -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/Chapter10/AdvancedTypeScript3Discogs/wwwroot/js/site.min.js -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 3" 33 | }, 34 | "version": "3.3.7", 35 | "_release": "3.3.7", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.7", 39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" 40 | }, 41 | "_source": "https://github.com/twbs/bootstrap.git", 42 | "_target": "v3.3.7", 43 | "_originalSource": "bootstrap", 44 | "_direct": true 45 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 4 | "version": "3.2.9", 5 | "_release": "3.2.9", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "v3.2.9", 9 | "commit": "a91f5401898e125f10771c5f5f0909d8c4c82396" 10 | }, 11 | "_source": "https://github.com/aspnet/jquery-validation-unobtrusive.git", 12 | "_target": "^3.2.9", 13 | "_originalSource": "jquery-validation-unobtrusive", 14 | "_direct": true 15 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "https://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jquery-validation/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.17.0", 31 | "_release": "1.17.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.17.0", 35 | "commit": "fc9b12d3bfaa2d0c04605855b896edb2934c0772" 36 | }, 37 | "_source": "https://github.com/jzaefferer/jquery-validation.git", 38 | "_target": "^1.17.0", 39 | "_originalSource": "jquery-validation", 40 | "_direct": true 41 | } -------------------------------------------------------------------------------- /Chapter10/AdvancedTypeScript3Discogs/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "3.3.1", 16 | "_release": "3.3.1", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "3.3.1", 20 | "commit": "9e8ec3d10fad04748176144f108d7355662ae75e" 21 | }, 22 | "_source": "https://github.com/jquery/jquery-dist.git", 23 | "_target": "^3.3.1", 24 | "_originalSource": "jquery", 25 | "_direct": true 26 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /node_modules/@types/bingmaps/README.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | > `npm install --save @types/bingmaps` 3 | 4 | # Summary 5 | This package contains type definitions for Microsoft.Maps 8.0 (Change set e6d7cc4) (https://github.com/Microsoft/Bing-Maps-V8-TypeScript-Definitions). 6 | 7 | # Details 8 | Files were exported from https://www.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/bingmaps 9 | 10 | Additional Details 11 | * Last updated: Mon, 08 Jan 2018 16:48:40 GMT 12 | * Dependencies: none 13 | * Global values: Microsoft 14 | 15 | # Credits 16 | These definitions were written by Ricky Brundritt . 17 | -------------------------------------------------------------------------------- /node_modules/@types/bingmaps/WellKnownText.d.ts: -------------------------------------------------------------------------------- 1 | declare module Microsoft.Maps { 2 | /** 3 | * Class responsible for readon/writing geo data in well known text format 4 | * @requires The Microsoft.Maps.WellKnownText module. 5 | */ 6 | export module WellKnownText { 7 | /** 8 | * Reads the data in wellknowntext format and returns the shapes. Multi-Geometry type shapes are returned as an array of shapes. 9 | * @param wkt The well known text string that needs to be parsed into shapes. 10 | * @param styles Styles to apply to the shapes. 11 | * @returns One of more shapes. 12 | */ 13 | export function read(wkt: string, styles?: IStylesOptions): IPrimitive | IPrimitive[]; 14 | 15 | /** 16 | * Writes the data into wellknowntext format. 17 | * @param data The data that needs to be serialized. 18 | * @returns Well known text formatted string. 19 | */ 20 | export function write(data: IPrimitive | IPrimitive[]): string; 21 | } 22 | } -------------------------------------------------------------------------------- /node_modules/bingmaps/.npmignore: -------------------------------------------------------------------------------- 1 | # Ignore the git folder 2 | .git/ 3 | 4 | # Ignore the build folder which has the NuGet package spec. 5 | build/ 6 | 7 | # Ignore the images folder. 8 | images/ 9 | 10 | #ignore the unnecessary markdown pages 11 | CONTRIBUTING.md 12 | README.md 13 | 14 | # Ignore the examples files 15 | /Example.ts 16 | 17 | # npm log 18 | /npm-debug.log -------------------------------------------------------------------------------- /node_modules/bingmaps/index.js: -------------------------------------------------------------------------------- 1 | /// -------------------------------------------------------------------------------- /node_modules/bingmaps/types/MicrosoftMaps/CustomMapStyles.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Advanced-TypeScript-3-Programming-Projects/6d2ecb4a9743c030fa47ad801da26f2c1fd74f8f/node_modules/bingmaps/types/MicrosoftMaps/CustomMapStyles.d.ts --------------------------------------------------------------------------------