├── .gitignore ├── README.md ├── behaviour ├── command │ ├── index.spec.ts │ ├── index.ts │ └── src │ │ ├── command.interface.ts │ │ ├── payment-commands │ │ ├── culqui.command.ts │ │ ├── dto │ │ │ └── credit-card.dto.ts │ │ ├── mercadopago.command.ts │ │ └── payu.command.ts │ │ └── payment-method.handler.ts ├── observer │ ├── index.spec.ts │ ├── index.ts │ └── src │ │ ├── impl │ │ ├── observer.interface.ts │ │ └── subject.abstract.ts │ │ ├── observers │ │ ├── email.observer.ts │ │ └── sms.observer.ts │ │ └── shopping-cart.ts └── strategy │ ├── index.spec.ts │ ├── index.ts │ └── src │ ├── checkout.ts │ ├── interfaces │ ├── payment-card-strategy.interface.ts │ ├── payment-gateway-strategy.interface.ts │ └── payment-strategy.interface.ts │ ├── mastercard.strategy.ts │ ├── paypal.strategy.ts │ └── visa.strategy.ts ├── creational ├── abstract-factory │ ├── index.spec.ts │ ├── index.ts │ └── src │ │ ├── abstract-factory.interface.ts │ │ ├── factories │ │ ├── connector.interface.ts │ │ ├── facebook │ │ │ ├── facebook-connector.ts │ │ │ ├── facebook-factory.ts │ │ │ └── facebook-publisher.ts │ │ ├── linkedin │ │ │ ├── linkedin-connector.ts │ │ │ ├── linkedin-factory.ts │ │ │ └── linkedin-publisher.ts │ │ ├── publisher.interface.ts │ │ └── slack │ │ │ ├── slack-connector.ts │ │ │ ├── slack-factory.ts │ │ │ └── slack-publisher.ts │ │ └── publisher.ts ├── factory │ ├── enums │ │ └── payment-type.ts │ ├── order.spec.ts │ ├── order.ts │ └── src │ │ ├── payment-method-factory.ts │ │ ├── payment-method.interface.ts │ │ └── types │ │ ├── MasterCard.ts │ │ ├── PayPal.ts │ │ └── Visa.ts └── singleton │ ├── config.json │ ├── my-configuration.spec.ts │ └── my-configuration.ts ├── package-lock.json ├── package.json ├── structural ├── adapter │ ├── index.spec.ts │ ├── index.ts │ └── src │ │ ├── providers │ │ ├── facebook-notification.ts │ │ ├── notification.interface.ts │ │ ├── slack-adapter-notification.ts │ │ └── slack-notification.ts │ │ └── services │ │ └── notification.service.ts ├── decorator │ ├── index.spec.ts │ ├── index.ts │ └── src │ │ ├── base-price.ts │ │ ├── customer.ts │ │ ├── decorators │ │ ├── special-price.decorator.ts │ │ └── vip-customer.decorator.ts │ │ ├── interfaces │ │ └── discount.interface.ts │ │ └── product.ts └── proxy │ ├── index.spec.ts │ ├── index.ts │ └── src │ ├── video-provider.interface.ts │ ├── video.proxy.ts │ └── youtube.api.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | 113 | .yarn/cache 114 | .yarn/unplugged 115 | .yarn/build-state.yml 116 | .pnp.* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design Patterns TypeScript 2 | Parte de nuestro curso gratuito de patrones de diseño con TypeScript que se encuentra disponible a través de nuestro canal de YouTube. 3 | 4 | Lo que buscamos a través de estos videos es ir más allá de que tecnología usar, sino más bien, entender los conceptos que conlleva el patrón y los problemas que resuelven. 5 | 6 | ## Lecciones 7 | Compartimos los enlaces a las lecciones del curso. 8 | 9 | ### Introducción 10 | En este primer video haremos una introducción a los patrones de diseño. 11 | https://www.youtube.com/watch?v=Yk5TXytE-gs 12 | 13 | ### Creation 14 | * Singleton - https://www.youtube.com/watch?v=Qckwuge7dpQ 15 | * Factory - https://www.youtube.com/watch?v=QP33nP-KNko 16 | * Abstract Factory - https://www.youtube.com/watch?v=JgejyeRyztI 17 | 18 | ### Structural 19 | * Adapter - https://www.youtube.com/watch?v=P5Ig9vtRy-w 20 | * Decorator - https://www.youtube.com/watch?v=WNlqIsUPp1g 21 | * Proxy - https://www.youtube.com/watch?v=K3EzQjJNJTo 22 | 23 | ### Behavior 24 | * Command - https://www.youtube.com/watch?v=OHm23zee9tU 25 | * Observer - https://www.youtube.com/watch?v=WUsOLZpBsjU 26 | * Strategy - https://www.youtube.com/watch?v=BfaWQ5IiJCc 27 | 28 | ## Suscríbete 29 | A nuestro canal para seguir subiendo más material y esten atentos a nuestros próximos videos de contenido gratuito. 30 | https://www.youtube.com/channel/UCjay76-vPuSqSEmDM6PD74Q?sub_confirmation=1 31 | -------------------------------------------------------------------------------- /behaviour/command/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { PaymentMethodHandler } from "./src/payment-method.handler"; 2 | import { CulquiCommand } from "./src/payment-commands/culqui.command"; 3 | import { CreditCardDto } from "./src/payment-commands/dto/credit-card.dto"; 4 | 5 | describe("Payment Method Handler", () => { 6 | it("success case", () => { 7 | const paymentMethodHandler = new PaymentMethodHandler(); 8 | 9 | const creditCard = new CreditCardDto( 10 | "visa", 11 | "Eduardo Rodríguez Patiño", 12 | "xxx-xxx-xxx-xxx", 13 | "xxx", 14 | 300.00 15 | ); 16 | 17 | paymentMethodHandler.process(new CulquiCommand(creditCard)); 18 | }); 19 | }); -------------------------------------------------------------------------------- /behaviour/command/index.ts: -------------------------------------------------------------------------------- 1 | import { PaymentMethodHandler } from "./src/payment-method.handler"; 2 | import { CulquiCommand } from "./src/payment-commands/culqui.command"; 3 | import { CreditCardDto } from "./src/payment-commands/dto/credit-card.dto"; 4 | import { PayUCommand } from "./src/payment-commands/payu.command"; 5 | import { MercadoPagoCommand } from "./src/payment-commands/mercadopago.command"; 6 | 7 | const creditCard = new CreditCardDto( 8 | "visa", 9 | "Eduardo Rodríguez Patiño", 10 | "xxx-xxx-xxx-xxx", 11 | "xxx", 12 | 300.00 13 | ); 14 | 15 | const paymentMethodHandler = new PaymentMethodHandler(); 16 | 17 | // example 1 18 | // paymentMethodHandler.process(new CulquiCommand(creditCard)); 19 | 20 | // example 2 21 | paymentMethodHandler.forceToProcess([ 22 | new CulquiCommand(creditCard), 23 | new PayUCommand(creditCard), 24 | new MercadoPagoCommand(creditCard) 25 | ]); -------------------------------------------------------------------------------- /behaviour/command/src/command.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ICommand { 2 | providerName: string; 3 | handle(): void; 4 | } -------------------------------------------------------------------------------- /behaviour/command/src/payment-commands/culqui.command.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "../command.interface"; 2 | import { CreditCardDto } from "./dto/credit-card.dto"; 3 | 4 | export class CulquiCommand implements ICommand { 5 | public readonly providerName: string = 'Culqui'; 6 | 7 | constructor(private readonly creditCardDef: CreditCardDto) {} 8 | 9 | handle(): void { 10 | console.log(`${this.providerName} has been triggered ..`); 11 | // your code goes here .. 12 | } 13 | } -------------------------------------------------------------------------------- /behaviour/command/src/payment-commands/dto/credit-card.dto.ts: -------------------------------------------------------------------------------- 1 | type CreditCardType = 'visa' | 'marstercard' | 'dinner'; 2 | 3 | export class CreditCardDto { 4 | constructor( 5 | private readonly cardtype: CreditCardType, 6 | private readonly cardCustomerFullName: string, 7 | private readonly cardNumber: string, 8 | private readonly cardCcv: string, 9 | private readonly transactionAmount: number 10 | ) { } 11 | } -------------------------------------------------------------------------------- /behaviour/command/src/payment-commands/mercadopago.command.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "../command.interface"; 2 | import { CreditCardDto } from "./dto/credit-card.dto"; 3 | 4 | export class MercadoPagoCommand implements ICommand { 5 | public readonly providerName: string = 'MercadoPago'; 6 | 7 | constructor(private readonly creditCardDef: CreditCardDto) {} 8 | 9 | handle(): void { 10 | console.log(`${this.providerName} has been triggered ..`); 11 | // your code goes here .. 12 | } 13 | } -------------------------------------------------------------------------------- /behaviour/command/src/payment-commands/payu.command.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "../command.interface"; 2 | import { CreditCardDto } from "./dto/credit-card.dto"; 3 | 4 | export class PayUCommand implements ICommand { 5 | public readonly providerName: string = 'PayU'; 6 | 7 | constructor(private readonly creditCardDef: CreditCardDto) {} 8 | 9 | handle(): void { 10 | console.log(`${this.providerName} has been triggered ..`); 11 | // your code goes here .. 12 | } 13 | } -------------------------------------------------------------------------------- /behaviour/command/src/payment-method.handler.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "./command.interface"; 2 | 3 | export class PaymentMethodHandler { 4 | process(command: ICommand): void { 5 | console.log('Payment method handler has been started'); 6 | command.handle(); 7 | } 8 | 9 | forceToProcess(commands: ICommand[]): void { 10 | for(const cmd of commands) { 11 | try { 12 | if(cmd.providerName === 'Culqui') { 13 | throw new Error(`${cmd.providerName} rejected the user credit card by fraud`); 14 | } 15 | 16 | cmd.handle(); 17 | break; 18 | } catch (error) { 19 | console.warn(`\tERR: ${error.message}`); 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /behaviour/observer/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { ShoppingCart, CartItem } from "./src/shopping-cart"; 2 | import { EmailObserver } from "./src/observers/email.observer"; 3 | import { SmsObserver } from "./src/observers/sms.observer"; 4 | 5 | describe("Shopping Cart", () => { 6 | it("success case", () => { 7 | const smsObserver = new SmsObserver(); 8 | const emailObserver = new EmailObserver(); 9 | const shoppingCart = new ShoppingCart(1, "Eduardo"); 10 | 11 | shoppingCart.attach(smsObserver); 12 | shoppingCart.attach(emailObserver); 13 | 14 | shoppingCart.add(new CartItem(1, "Electric Guitar Shur", 1, 2800)); 15 | 16 | shoppingCart.purchase(); 17 | }); 18 | }); -------------------------------------------------------------------------------- /behaviour/observer/index.ts: -------------------------------------------------------------------------------- 1 | import { ShoppingCart, CartItem } from "./src/shopping-cart"; 2 | import { EmailObserver } from "./src/observers/email.observer"; 3 | import { SmsObserver } from "./src/observers/sms.observer"; 4 | 5 | // Observers 6 | const smsObserver = new SmsObserver(); 7 | const emailObserver = new EmailObserver(); 8 | 9 | // Subject 10 | const shoppingCart = new ShoppingCart(1, "Eduardo"); 11 | 12 | shoppingCart.attach(smsObserver); 13 | shoppingCart.attach(emailObserver); 14 | 15 | shoppingCart.add(new CartItem(1, "Electric Guitar Shur", 1, 2800)); 16 | shoppingCart.add(new CartItem(2, "Amp 60w Fender Twin Reverb", 1, 1400)); 17 | shoppingCart.add(new CartItem(3, "Addario 009 Guitar Strings", 10, 7.5)); 18 | 19 | shoppingCart.purchase(); -------------------------------------------------------------------------------- /behaviour/observer/src/impl/observer.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Observer { 2 | update(subject: any): void; 3 | } -------------------------------------------------------------------------------- /behaviour/observer/src/impl/subject.abstract.ts: -------------------------------------------------------------------------------- 1 | import { Observer } from "./observer.interface"; 2 | 3 | export abstract class Subject { 4 | private observers: Observer[] = []; 5 | 6 | public attach(observer: Observer): void { 7 | if (!this.observers.some(x => x === observer)) { 8 | this.observers.push(observer); 9 | } else { 10 | throw new Error('Observer has already been registered.'); 11 | } 12 | } 13 | 14 | public detach(observer: Observer): void { 15 | this.observers.filter(x => x !== observer); 16 | } 17 | 18 | protected notify(message: any): void { 19 | this.observers.forEach(x => x.update(message)); 20 | } 21 | }; -------------------------------------------------------------------------------- /behaviour/observer/src/observers/email.observer.ts: -------------------------------------------------------------------------------- 1 | import { Order } from "../shopping-cart"; 2 | import { Observer } from "../impl/observer.interface"; 3 | 4 | export class EmailObserver implements Observer { 5 | update(message: Order): void { 6 | console.log(`EMAIL: Your order #${message.id} has been approved.`); 7 | } 8 | } -------------------------------------------------------------------------------- /behaviour/observer/src/observers/sms.observer.ts: -------------------------------------------------------------------------------- 1 | import { Order } from "../shopping-cart"; 2 | import { Observer } from "../impl/observer.interface"; 3 | 4 | export class SmsObserver implements Observer { 5 | update(message: Order): void { 6 | const total = message.items.map(x => x.quantity * x.unitPrice).reduce((a, b) => a + b); 7 | console.log(`SMS: ${message.userFirstName}, your order ${message.id} by the amount of $${total} has been approved.`); 8 | } 9 | } -------------------------------------------------------------------------------- /behaviour/observer/src/shopping-cart.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from "./impl/subject.abstract"; 2 | 3 | let orderNumber = 1; 4 | 5 | export class CartItem { 6 | constructor( 7 | public id: number, 8 | public name: string, 9 | public quantity: number, 10 | public unitPrice: number 11 | ) { } 12 | } 13 | 14 | export class Order { 15 | public readonly id: string; 16 | 17 | constructor( 18 | public readonly userId: number, 19 | public readonly userFirstName: string, 20 | public readonly items: CartItem[]) { 21 | const now = new Date(); 22 | this.id = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}${orderNumber.toString().padStart(4, '0')}`; 23 | 24 | orderNumber++; 25 | } 26 | } 27 | 28 | export class ShoppingCart extends Subject { 29 | constructor(private userId: number, private userFirstName: string) { 30 | super(); 31 | } 32 | 33 | private readonly items: CartItem[] = []; 34 | 35 | add(item: CartItem) { 36 | const CartItem = this.items.find(x => x.id === item.id); 37 | 38 | if (CartItem) { 39 | throw new Error('The product has already been added to the shopping cart.') 40 | } else { 41 | this.items.push(item); 42 | } 43 | } 44 | 45 | purchase() { 46 | // your business logic goes here .. 47 | 48 | const order = new Order(this.userId, this.userFirstName, this.items); 49 | 50 | this.notify(order); 51 | } 52 | } -------------------------------------------------------------------------------- /behaviour/strategy/index.spec.ts: -------------------------------------------------------------------------------- 1 | import "mocha"; 2 | import { expect } from "chai"; 3 | import { Checkout } from "./src/checkout"; 4 | import { PayPalStrategy } from "./src/paypal.strategy"; 5 | 6 | const checkout = new Checkout(); 7 | 8 | let userId = "usr-001", 9 | useEmail = "eduardo@kodoti.com", 10 | amount = 2000; 11 | 12 | describe("Strategy Pattern", () => { 13 | it("successful paypal usage", () => { 14 | checkout.setStrategy( 15 | new PayPalStrategy(useEmail) 16 | ); 17 | 18 | const { isSuccess } = checkout.execute(userId, amount); 19 | 20 | expect(isSuccess).to.equal(true); 21 | }); 22 | }); -------------------------------------------------------------------------------- /behaviour/strategy/index.ts: -------------------------------------------------------------------------------- 1 | import { Checkout } from "./src/checkout"; 2 | import { MastercardStrategy } from "./src/mastercard.strategy"; 3 | import { PayPalStrategy } from "./src/paypal.strategy"; 4 | import { VisaStrategy } from "./src/visa.strategy"; 5 | 6 | const checkout = new Checkout(); 7 | 8 | let userId = "usr-001", 9 | useEmail = "eduardo@kodoti.com", 10 | cardNumber = "000-000-000-000", 11 | cvv = "123", 12 | amount = 2000, 13 | paymentMethod = "paypal"; 14 | 15 | 16 | if (paymentMethod === "paypal") { 17 | checkout.setStrategy( 18 | new PayPalStrategy(useEmail) 19 | ); 20 | } 21 | 22 | if (paymentMethod === "visa") { 23 | checkout.setStrategy( 24 | new VisaStrategy(cardNumber, cvv) 25 | ); 26 | } 27 | 28 | if (paymentMethod === "mastercard") { 29 | checkout.setStrategy( 30 | new MastercardStrategy(cardNumber, cvv) 31 | ); 32 | } 33 | 34 | checkout.execute(userId, amount); -------------------------------------------------------------------------------- /behaviour/strategy/src/checkout.ts: -------------------------------------------------------------------------------- 1 | import { PaymentResponse, PaymentStrategy } from "./interfaces/payment-strategy.interface"; 2 | 3 | export class Checkout { 4 | private context?: PaymentStrategy; 5 | 6 | public setStrategy(context: PaymentStrategy) { 7 | this.context = context; 8 | } 9 | 10 | public execute(userId: string, amount: number): PaymentResponse { 11 | if (!this.context) { 12 | throw new Error('Context must be defined before running.'); 13 | } 14 | 15 | return this.context.execute(userId, amount); 16 | } 17 | } -------------------------------------------------------------------------------- /behaviour/strategy/src/interfaces/payment-card-strategy.interface.ts: -------------------------------------------------------------------------------- 1 | import { PaymentStrategy } from "./payment-strategy.interface"; 2 | 3 | export interface PaymentCardStrategy extends PaymentStrategy { 4 | cardNumber: string; 5 | cvv: string; 6 | } -------------------------------------------------------------------------------- /behaviour/strategy/src/interfaces/payment-gateway-strategy.interface.ts: -------------------------------------------------------------------------------- 1 | import { PaymentStrategy } from "./payment-strategy.interface"; 2 | 3 | export interface PaymentGatewayStrategy extends PaymentStrategy { 4 | userEmail: string; 5 | } -------------------------------------------------------------------------------- /behaviour/strategy/src/interfaces/payment-strategy.interface.ts: -------------------------------------------------------------------------------- 1 | export interface PaymentResponse { 2 | isSuccess: boolean; 3 | errorMessage?: string; 4 | } 5 | 6 | export interface PaymentStrategy { 7 | execute(userId: string, amount: number): PaymentResponse; 8 | } -------------------------------------------------------------------------------- /behaviour/strategy/src/mastercard.strategy.ts: -------------------------------------------------------------------------------- 1 | import { PaymentCardStrategy } from "./interfaces/payment-card-strategy.interface"; 2 | import { PaymentResponse } from "./interfaces/payment-strategy.interface"; 3 | 4 | export class MastercardStrategy implements PaymentCardStrategy { 5 | constructor(public cardNumber: string, public cvv: string) { } 6 | 7 | execute(userId: string, amount: number): PaymentResponse { 8 | console.log(`Masterdcard approved the transaction for ${userId} in the amount of US$ ${amount}.`); 9 | return { isSuccess: true }; 10 | } 11 | } -------------------------------------------------------------------------------- /behaviour/strategy/src/paypal.strategy.ts: -------------------------------------------------------------------------------- 1 | import { PaymentGatewayStrategy } from "./interfaces/payment-gateway-strategy.interface"; 2 | import { PaymentResponse } from "./interfaces/payment-strategy.interface"; 3 | 4 | export class PayPalStrategy implements PaymentGatewayStrategy { 5 | constructor(public userEmail: string) { } 6 | 7 | execute(userId: string, amount: number): PaymentResponse { 8 | console.log(`PayPal approved the transaction for ${userId} in the amount of US$ ${amount}.`); 9 | return { isSuccess: true }; 10 | } 11 | } -------------------------------------------------------------------------------- /behaviour/strategy/src/visa.strategy.ts: -------------------------------------------------------------------------------- 1 | import { PaymentCardStrategy } from "./interfaces/payment-card-strategy.interface"; 2 | import { PaymentResponse } from "./interfaces/payment-strategy.interface"; 3 | 4 | export class VisaStrategy implements PaymentCardStrategy { 5 | constructor(public cardNumber: string, public cvv: string) { } 6 | 7 | execute(userId: string, amount: number): PaymentResponse { 8 | console.log(`Vista approved the transaction for ${userId} in the amount of US$ ${amount}.`); 9 | return { isSuccess: true }; 10 | } 11 | } -------------------------------------------------------------------------------- /creational/abstract-factory/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import "mocha"; 3 | 4 | import FacebookFactory from "./src/factories/facebook/facebook-factory"; 5 | import LinkedinFactory from "./src/factories/linkedin/linkedin-factory"; 6 | import SlackFactory from "./src/factories/slack/slack-factory"; 7 | import FacebookConnector from "./src/factories/facebook/facebook-connector"; 8 | import FacebookPublisher from "./src/factories/facebook/facebook-publisher"; 9 | import LinkedinConnector from "./src/factories/linkedin/linkedin-connector"; 10 | import LinkedinPublisher from "./src/factories/linkedin/linkedin-publisher"; 11 | import SlackConnector from "./src/factories/slack/slack-connector"; 12 | import SlackPublisher from "./src/factories/slack/slack-publisher"; 13 | 14 | const facebookFactory = new FacebookFactory(), 15 | linkedinFactory = new LinkedinFactory(), 16 | slackFactory = new SlackFactory(); 17 | 18 | describe("Facebook Publisher", () => { 19 | it("It must be a Facebook connector", () => { 20 | expect(true).to.equal(facebookFactory.getConnector() instanceof FacebookConnector); 21 | }); 22 | 23 | it("It must be a Facebook publisher", () => { 24 | const connector = facebookFactory.getConnector(); 25 | expect(true).to.equal(facebookFactory.getPublisher(connector) instanceof FacebookPublisher); 26 | }); 27 | }); 28 | 29 | describe("Linkedin Publisher", () => { 30 | it("It must be a Linkedin connector", () => { 31 | expect(true).to.equal(linkedinFactory.getConnector() instanceof LinkedinConnector); 32 | }); 33 | 34 | it("It must be a Linkedin publisher", () => { 35 | const connector = linkedinFactory.getConnector(); 36 | expect(true).to.equal(linkedinFactory.getPublisher(connector) instanceof LinkedinPublisher); 37 | }); 38 | }); 39 | 40 | describe("Slack Publisher", () => { 41 | it("It must be a Slack connector", () => { 42 | expect(true).to.equal(slackFactory.getConnector() instanceof SlackConnector); 43 | }); 44 | 45 | it("It must be a Slack publisher", () => { 46 | const connector = slackFactory.getConnector(); 47 | expect(true).to.equal(slackFactory.getPublisher(connector) instanceof SlackPublisher); 48 | }); 49 | }); -------------------------------------------------------------------------------- /creational/abstract-factory/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import Publisher from "./src/publisher"; 3 | import FacebookFactory from "./src/factories/facebook/facebook-factory"; 4 | import LinkedinFactory from "./src/factories/linkedin/linkedin-factory"; 5 | import SlackFactory from "./src/factories/slack/slack-factory"; 6 | 7 | const content = ` 8 | Solo por hoy, cualquier curso a US$ 5.99, 9 | 10 | 👉 https://kodoti.com/super-oferta 11 | `; 12 | 13 | const publisher = new Publisher(content); 14 | 15 | publisher.send(new FacebookFactory()); 16 | publisher.send(new LinkedinFactory()); 17 | publisher.send(new SlackFactory()); -------------------------------------------------------------------------------- /creational/abstract-factory/src/abstract-factory.interface.ts: -------------------------------------------------------------------------------- 1 | import IConnector from "./factories/connector.interface"; 2 | import IPublisher from "./factories/publisher.interface"; 3 | 4 | export default interface IAbstractFactory { 5 | getConnector(): IConnector; 6 | getPublisher(connector: IConnector): IPublisher; 7 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/connector.interface.ts: -------------------------------------------------------------------------------- 1 | export default interface IConnector { 2 | open(): void; 3 | close(): void; 4 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/facebook/facebook-connector.ts: -------------------------------------------------------------------------------- 1 | import IConnector from "../connector.interface"; 2 | 3 | export default class FacebookConnector implements IConnector { 4 | open(): void { 5 | // Logic to make a valid connection 6 | } 7 | 8 | close(): void { 9 | // Logic to close the current connection 10 | } 11 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/facebook/facebook-factory.ts: -------------------------------------------------------------------------------- 1 | import IAbstractFactory from "../../abstract-factory.interface"; 2 | import IConnector from "../connector.interface"; 3 | import FacebookConnector from "./facebook-connector"; 4 | import IPublisher from "../publisher.interface"; 5 | import FacebookPublisher from "./facebook-publisher"; 6 | 7 | export default class FacebookFactory implements IAbstractFactory { 8 | getConnector(): IConnector { 9 | return new FacebookConnector(); 10 | } 11 | 12 | getPublisher(connector: IConnector): IPublisher { 13 | return new FacebookPublisher(connector); 14 | } 15 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/facebook/facebook-publisher.ts: -------------------------------------------------------------------------------- 1 | import IPublisher from "../publisher.interface"; 2 | import IConnector from "../connector.interface"; 3 | 4 | export default class FacebookPublisher implements IPublisher { 5 | constructor(private connector: IConnector) { } 6 | 7 | publish(content: string): void { 8 | // Your logic to publish on Facebook 9 | console.log("Facebook"); 10 | console.log(content); 11 | } 12 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/linkedin/linkedin-connector.ts: -------------------------------------------------------------------------------- 1 | import IConnector from "../connector.interface"; 2 | 3 | export default class LinkedinConnector implements IConnector { 4 | open(): void { 5 | // Logic to make a valid connection 6 | } 7 | 8 | close(): void { 9 | // Logic to close the current connection 10 | } 11 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/linkedin/linkedin-factory.ts: -------------------------------------------------------------------------------- 1 | import IAbstractFactory from "../../abstract-factory.interface"; 2 | import IConnector from "../connector.interface"; 3 | import IPublisher from "../publisher.interface"; 4 | import LinkedinPublisher from "./linkedin-publisher"; 5 | import LinkedinConnector from "./linkedin-connector"; 6 | 7 | export default class LinkedinFactory implements IAbstractFactory { 8 | getConnector(): IConnector { 9 | return new LinkedinConnector(); 10 | } 11 | 12 | getPublisher(connector: IConnector): IPublisher { 13 | return new LinkedinPublisher(connector); 14 | } 15 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/linkedin/linkedin-publisher.ts: -------------------------------------------------------------------------------- 1 | import IPublisher from "../publisher.interface"; 2 | import IConnector from "../connector.interface"; 3 | 4 | export default class LinkedinPublisher implements IPublisher { 5 | constructor(private connector: IConnector) { } 6 | 7 | publish(content: string): void { 8 | // Your logic to publish on Linkedin 9 | console.log("Linkedin"); 10 | console.log(content); 11 | } 12 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/publisher.interface.ts: -------------------------------------------------------------------------------- 1 | export default interface IPublisher { 2 | publish(content: string): void; 3 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/slack/slack-connector.ts: -------------------------------------------------------------------------------- 1 | import IConnector from "../connector.interface"; 2 | 3 | export default class SlackConnector implements IConnector { 4 | open(): void { 5 | // Logic to make a valid connection 6 | } 7 | 8 | close(): void { 9 | // Logic to close the current connection 10 | } 11 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/slack/slack-factory.ts: -------------------------------------------------------------------------------- 1 | import IAbstractFactory from "../../abstract-factory.interface"; 2 | import IConnector from "../connector.interface"; 3 | import IPublisher from "../publisher.interface"; 4 | import SlackPublisher from "./slack-publisher"; 5 | import SlackConnector from "./slack-connector"; 6 | 7 | export default class SlackFactory implements IAbstractFactory { 8 | getConnector(): IConnector { 9 | return new SlackConnector(); 10 | } 11 | 12 | getPublisher(connector: IConnector): IPublisher { 13 | return new SlackPublisher(connector); 14 | } 15 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/factories/slack/slack-publisher.ts: -------------------------------------------------------------------------------- 1 | import IPublisher from "../publisher.interface"; 2 | import IConnector from "../connector.interface"; 3 | 4 | export default class SlackPublisher implements IPublisher { 5 | constructor(private connector: IConnector) { } 6 | 7 | publish(content: string): void { 8 | // Your logic to publish on Slack 9 | console.log("Slack"); 10 | console.log(content); 11 | } 12 | } -------------------------------------------------------------------------------- /creational/abstract-factory/src/publisher.ts: -------------------------------------------------------------------------------- 1 | import IAbstractFactory from "./abstract-factory.interface"; 2 | 3 | export default class Publisher { 4 | constructor(private content: string) { } 5 | 6 | public send(factory: IAbstractFactory) { 7 | const connector = factory.getConnector(); 8 | const publisher = factory.getPublisher(connector); 9 | 10 | connector.open(); 11 | publisher.publish(this.content); 12 | connector.close(); 13 | } 14 | } -------------------------------------------------------------------------------- /creational/factory/enums/payment-type.ts: -------------------------------------------------------------------------------- 1 | enum PaymentType { 2 | Visa, 3 | Mastercard, 4 | PayPal 5 | }; 6 | 7 | export default PaymentType; -------------------------------------------------------------------------------- /creational/factory/order.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import "mocha"; 3 | 4 | import Order from "./order"; 5 | import PaymentType from "./enums/payment-type"; 6 | 7 | import Visa from "./src/types/Visa"; 8 | import MasterCard from "./src/types/MasterCard"; 9 | import PayPal from "./src/types/PayPal"; 10 | 11 | let order1 = new Order(PaymentType.Visa, 100), 12 | order2 = new Order(PaymentType.Mastercard, 100), 13 | order3 = new Order(PaymentType.PayPal, 100); 14 | 15 | order1.create(); 16 | order2.create(); 17 | order3.create(); 18 | 19 | describe("Order - Visa", () => { 20 | it("Order must be paid by visa", () => { 21 | expect(true).to.equal(order1.paymentType instanceof Visa); 22 | }); 23 | 24 | it("Order commission must be 5", () => { 25 | expect(5).to.equal(order1.commission); 26 | }); 27 | }); 28 | 29 | describe("Order - Mastercard", () => { 30 | it("Order must be paid by mastercard", () => { 31 | expect(true).to.equal(order2.paymentType instanceof MasterCard); 32 | }); 33 | 34 | it("Order commission must be 4", () => { 35 | expect(4).to.equal(order2.commission); 36 | }); 37 | }); 38 | 39 | describe("Order - PayPal", () => { 40 | it("Order must be paid by paypal", () => { 41 | expect(true).to.equal(order3.paymentType instanceof PayPal); 42 | }); 43 | 44 | it("Order commission must be 6", () => { 45 | expect(6).to.equal(order3.commission); 46 | }); 47 | }); -------------------------------------------------------------------------------- /creational/factory/order.ts: -------------------------------------------------------------------------------- 1 | import PaymentType from "./enums/payment-type"; 2 | import IPaymentMethod from "./src/payment-method.interface"; 3 | import PaymentMethodFactory from "./src/payment-method-factory"; 4 | 5 | export default class Order { 6 | public paymentType?: IPaymentMethod; 7 | public commission: number = 0; 8 | 9 | constructor( 10 | private type: PaymentType, 11 | public amount: number) { } 12 | 13 | public create(): void { 14 | // set payment type 15 | this.paymentType = PaymentMethodFactory.createPaymentType(this.type); 16 | 17 | // calculate commission 18 | this.commission = this.paymentType.comission * this.amount; 19 | 20 | // ... 21 | } 22 | } -------------------------------------------------------------------------------- /creational/factory/src/payment-method-factory.ts: -------------------------------------------------------------------------------- 1 | import PaymentType from "../enums/payment-type"; 2 | import IPaymentMethod from "./payment-method.interface"; 3 | import MasterCard from "./types/MasterCard"; 4 | import PayPal from "./types/PayPal"; 5 | import Visa from "./types/Visa"; 6 | 7 | export default class PaymentMethodFactory { 8 | public static createPaymentType(type: PaymentType): IPaymentMethod { 9 | if (type === PaymentType.Mastercard) { 10 | return new MasterCard(); 11 | } 12 | 13 | if (type === PaymentType.PayPal) { 14 | return new PayPal(); 15 | } 16 | 17 | if (type === PaymentType.Visa) { 18 | return new Visa(); 19 | } 20 | 21 | throw new Error("Invalid payment method type."); 22 | } 23 | } -------------------------------------------------------------------------------- /creational/factory/src/payment-method.interface.ts: -------------------------------------------------------------------------------- 1 | export default interface IPaymentMethod { 2 | comission:number; 3 | } -------------------------------------------------------------------------------- /creational/factory/src/types/MasterCard.ts: -------------------------------------------------------------------------------- 1 | import IPaymentMethod from "../payment-method.interface"; 2 | 3 | export default class MasterCard implements IPaymentMethod { 4 | get comission(): number { 5 | return 0.04; 6 | } 7 | } -------------------------------------------------------------------------------- /creational/factory/src/types/PayPal.ts: -------------------------------------------------------------------------------- 1 | import IPaymentMethod from "../payment-method.interface"; 2 | 3 | export default class PayPal implements IPaymentMethod { 4 | get comission(): number { 5 | return 0.06; 6 | } 7 | } -------------------------------------------------------------------------------- /creational/factory/src/types/Visa.ts: -------------------------------------------------------------------------------- 1 | import IPaymentMethod from "../payment-method.interface"; 2 | 3 | export default class Visa implements IPaymentMethod { 4 | get comission(): number { 5 | return 0.05; 6 | } 7 | } -------------------------------------------------------------------------------- /creational/singleton/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "enviroment": "development", 3 | "connectionString": "Server=myServerAddress;Database=myDataBase;UserId=myUsername;Password=myPassword;", 4 | "apiUrl": "https://api.kodoti.com/" 5 | } -------------------------------------------------------------------------------- /creational/singleton/my-configuration.spec.ts: -------------------------------------------------------------------------------- 1 | import MyConfiguration from "./my-configuration"; 2 | 3 | import { expect } from "chai"; 4 | import "mocha"; 5 | 6 | let config = MyConfiguration.getInstance(); 7 | 8 | describe("My Configuration Class", () => { 9 | it("object should be not null", () => { 10 | expect(config !== null).to.equal(true); 11 | }); 12 | 13 | it("objects should be equals", () => { 14 | let config2 = MyConfiguration.getInstance(); 15 | 16 | expect(config === config2).to.equal(true); 17 | }); 18 | 19 | it("enviroment property should be development", () => { 20 | expect(config.enviroment === "development").to.equal(true); 21 | }); 22 | }); -------------------------------------------------------------------------------- /creational/singleton/my-configuration.ts: -------------------------------------------------------------------------------- 1 | import config from "./config.json"; 2 | 3 | export default class MyConfiguration { 4 | private static instance: MyConfiguration; 5 | 6 | private static _connectionString: string; 7 | private static _environment: string; 8 | private static _apiUrl: string; 9 | 10 | private constructor() { } 11 | 12 | private static initialize(): void { 13 | this._connectionString = config.connectionString; 14 | this._environment = config.enviroment; 15 | this._apiUrl = config.apiUrl; 16 | } 17 | 18 | public static getInstance(): MyConfiguration { 19 | if (!this.instance) { 20 | this.initialize(); 21 | this.instance = new MyConfiguration(); 22 | } 23 | 24 | return this.instance; 25 | } 26 | 27 | get connectionString(): string { 28 | return MyConfiguration._connectionString; 29 | } 30 | 31 | get enviroment(): string { 32 | return MyConfiguration._environment; 33 | } 34 | 35 | get apiUrl(): string { 36 | return MyConfiguration._apiUrl; 37 | } 38 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "patrones", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/chai": { 8 | "version": "4.2.11", 9 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.11.tgz", 10 | "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", 11 | "dev": true 12 | }, 13 | "@types/mocha": { 14 | "version": "7.0.2", 15 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", 16 | "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", 17 | "dev": true 18 | }, 19 | "ansi-colors": { 20 | "version": "3.2.3", 21 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", 22 | "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", 23 | "dev": true 24 | }, 25 | "ansi-regex": { 26 | "version": "3.0.0", 27 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 28 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 29 | "dev": true 30 | }, 31 | "ansi-styles": { 32 | "version": "3.2.1", 33 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 34 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 35 | "dev": true, 36 | "requires": { 37 | "color-convert": "^1.9.0" 38 | } 39 | }, 40 | "anymatch": { 41 | "version": "3.1.1", 42 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", 43 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", 44 | "dev": true, 45 | "requires": { 46 | "normalize-path": "^3.0.0", 47 | "picomatch": "^2.0.4" 48 | } 49 | }, 50 | "arg": { 51 | "version": "4.1.3", 52 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 53 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 54 | "dev": true 55 | }, 56 | "argparse": { 57 | "version": "1.0.10", 58 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 59 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 60 | "dev": true, 61 | "requires": { 62 | "sprintf-js": "~1.0.2" 63 | } 64 | }, 65 | "assertion-error": { 66 | "version": "1.1.0", 67 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 68 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 69 | "dev": true 70 | }, 71 | "balanced-match": { 72 | "version": "1.0.0", 73 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 74 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 75 | "dev": true 76 | }, 77 | "binary-extensions": { 78 | "version": "2.0.0", 79 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", 80 | "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", 81 | "dev": true 82 | }, 83 | "brace-expansion": { 84 | "version": "1.1.11", 85 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 86 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 87 | "dev": true, 88 | "requires": { 89 | "balanced-match": "^1.0.0", 90 | "concat-map": "0.0.1" 91 | } 92 | }, 93 | "braces": { 94 | "version": "3.0.2", 95 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 96 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 97 | "dev": true, 98 | "requires": { 99 | "fill-range": "^7.0.1" 100 | } 101 | }, 102 | "browser-stdout": { 103 | "version": "1.3.1", 104 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 105 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 106 | "dev": true 107 | }, 108 | "buffer-from": { 109 | "version": "1.1.1", 110 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 111 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 112 | "dev": true 113 | }, 114 | "chai": { 115 | "version": "4.2.0", 116 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", 117 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", 118 | "dev": true, 119 | "requires": { 120 | "assertion-error": "^1.1.0", 121 | "check-error": "^1.0.2", 122 | "deep-eql": "^3.0.1", 123 | "get-func-name": "^2.0.0", 124 | "pathval": "^1.1.0", 125 | "type-detect": "^4.0.5" 126 | } 127 | }, 128 | "chalk": { 129 | "version": "2.4.2", 130 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 131 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 132 | "dev": true, 133 | "requires": { 134 | "ansi-styles": "^3.2.1", 135 | "escape-string-regexp": "^1.0.5", 136 | "supports-color": "^5.3.0" 137 | }, 138 | "dependencies": { 139 | "supports-color": { 140 | "version": "5.5.0", 141 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 142 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 143 | "dev": true, 144 | "requires": { 145 | "has-flag": "^3.0.0" 146 | } 147 | } 148 | } 149 | }, 150 | "check-error": { 151 | "version": "1.0.2", 152 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 153 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 154 | "dev": true 155 | }, 156 | "chokidar": { 157 | "version": "3.3.0", 158 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", 159 | "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", 160 | "dev": true, 161 | "requires": { 162 | "anymatch": "~3.1.1", 163 | "braces": "~3.0.2", 164 | "fsevents": "~2.1.1", 165 | "glob-parent": "~5.1.0", 166 | "is-binary-path": "~2.1.0", 167 | "is-glob": "~4.0.1", 168 | "normalize-path": "~3.0.0", 169 | "readdirp": "~3.2.0" 170 | } 171 | }, 172 | "cliui": { 173 | "version": "5.0.0", 174 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 175 | "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", 176 | "dev": true, 177 | "requires": { 178 | "string-width": "^3.1.0", 179 | "strip-ansi": "^5.2.0", 180 | "wrap-ansi": "^5.1.0" 181 | }, 182 | "dependencies": { 183 | "ansi-regex": { 184 | "version": "4.1.0", 185 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 186 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 187 | "dev": true 188 | }, 189 | "string-width": { 190 | "version": "3.1.0", 191 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 192 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 193 | "dev": true, 194 | "requires": { 195 | "emoji-regex": "^7.0.1", 196 | "is-fullwidth-code-point": "^2.0.0", 197 | "strip-ansi": "^5.1.0" 198 | } 199 | }, 200 | "strip-ansi": { 201 | "version": "5.2.0", 202 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 203 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 204 | "dev": true, 205 | "requires": { 206 | "ansi-regex": "^4.1.0" 207 | } 208 | } 209 | } 210 | }, 211 | "color-convert": { 212 | "version": "1.9.3", 213 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 214 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 215 | "dev": true, 216 | "requires": { 217 | "color-name": "1.1.3" 218 | } 219 | }, 220 | "color-name": { 221 | "version": "1.1.3", 222 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 223 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 224 | "dev": true 225 | }, 226 | "concat-map": { 227 | "version": "0.0.1", 228 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 229 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 230 | "dev": true 231 | }, 232 | "debug": { 233 | "version": "3.2.6", 234 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 235 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 236 | "dev": true, 237 | "requires": { 238 | "ms": "^2.1.1" 239 | } 240 | }, 241 | "decamelize": { 242 | "version": "1.2.0", 243 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 244 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 245 | "dev": true 246 | }, 247 | "deep-eql": { 248 | "version": "3.0.1", 249 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 250 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 251 | "dev": true, 252 | "requires": { 253 | "type-detect": "^4.0.0" 254 | } 255 | }, 256 | "define-properties": { 257 | "version": "1.1.3", 258 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 259 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 260 | "dev": true, 261 | "requires": { 262 | "object-keys": "^1.0.12" 263 | } 264 | }, 265 | "diff": { 266 | "version": "3.5.0", 267 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 268 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 269 | "dev": true 270 | }, 271 | "emoji-regex": { 272 | "version": "7.0.3", 273 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 274 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 275 | "dev": true 276 | }, 277 | "es-abstract": { 278 | "version": "1.17.5", 279 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", 280 | "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", 281 | "dev": true, 282 | "requires": { 283 | "es-to-primitive": "^1.2.1", 284 | "function-bind": "^1.1.1", 285 | "has": "^1.0.3", 286 | "has-symbols": "^1.0.1", 287 | "is-callable": "^1.1.5", 288 | "is-regex": "^1.0.5", 289 | "object-inspect": "^1.7.0", 290 | "object-keys": "^1.1.1", 291 | "object.assign": "^4.1.0", 292 | "string.prototype.trimleft": "^2.1.1", 293 | "string.prototype.trimright": "^2.1.1" 294 | } 295 | }, 296 | "es-to-primitive": { 297 | "version": "1.2.1", 298 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 299 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 300 | "dev": true, 301 | "requires": { 302 | "is-callable": "^1.1.4", 303 | "is-date-object": "^1.0.1", 304 | "is-symbol": "^1.0.2" 305 | } 306 | }, 307 | "escape-string-regexp": { 308 | "version": "1.0.5", 309 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 310 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 311 | "dev": true 312 | }, 313 | "esprima": { 314 | "version": "4.0.1", 315 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 316 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 317 | "dev": true 318 | }, 319 | "fill-range": { 320 | "version": "7.0.1", 321 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 322 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 323 | "dev": true, 324 | "requires": { 325 | "to-regex-range": "^5.0.1" 326 | } 327 | }, 328 | "flat": { 329 | "version": "4.1.0", 330 | "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", 331 | "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", 332 | "dev": true, 333 | "requires": { 334 | "is-buffer": "~2.0.3" 335 | } 336 | }, 337 | "fs.realpath": { 338 | "version": "1.0.0", 339 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 340 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 341 | "dev": true 342 | }, 343 | "fsevents": { 344 | "version": "2.1.3", 345 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", 346 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", 347 | "dev": true, 348 | "optional": true 349 | }, 350 | "function-bind": { 351 | "version": "1.1.1", 352 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 353 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 354 | "dev": true 355 | }, 356 | "get-caller-file": { 357 | "version": "2.0.5", 358 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 359 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 360 | "dev": true 361 | }, 362 | "get-func-name": { 363 | "version": "2.0.0", 364 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 365 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 366 | "dev": true 367 | }, 368 | "glob-parent": { 369 | "version": "5.1.1", 370 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", 371 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", 372 | "dev": true, 373 | "requires": { 374 | "is-glob": "^4.0.1" 375 | } 376 | }, 377 | "growl": { 378 | "version": "1.10.5", 379 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 380 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 381 | "dev": true 382 | }, 383 | "has": { 384 | "version": "1.0.3", 385 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 386 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 387 | "dev": true, 388 | "requires": { 389 | "function-bind": "^1.1.1" 390 | } 391 | }, 392 | "has-flag": { 393 | "version": "3.0.0", 394 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 395 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 396 | "dev": true 397 | }, 398 | "has-symbols": { 399 | "version": "1.0.1", 400 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 401 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", 402 | "dev": true 403 | }, 404 | "he": { 405 | "version": "1.2.0", 406 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 407 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 408 | "dev": true 409 | }, 410 | "inflight": { 411 | "version": "1.0.6", 412 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 413 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 414 | "dev": true, 415 | "requires": { 416 | "once": "^1.3.0", 417 | "wrappy": "1" 418 | } 419 | }, 420 | "inherits": { 421 | "version": "2.0.4", 422 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 423 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 424 | "dev": true 425 | }, 426 | "is-binary-path": { 427 | "version": "2.1.0", 428 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 429 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 430 | "dev": true, 431 | "requires": { 432 | "binary-extensions": "^2.0.0" 433 | } 434 | }, 435 | "is-buffer": { 436 | "version": "2.0.4", 437 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", 438 | "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", 439 | "dev": true 440 | }, 441 | "is-callable": { 442 | "version": "1.1.5", 443 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", 444 | "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", 445 | "dev": true 446 | }, 447 | "is-date-object": { 448 | "version": "1.0.2", 449 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 450 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", 451 | "dev": true 452 | }, 453 | "is-extglob": { 454 | "version": "2.1.1", 455 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 456 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 457 | "dev": true 458 | }, 459 | "is-fullwidth-code-point": { 460 | "version": "2.0.0", 461 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 462 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 463 | "dev": true 464 | }, 465 | "is-glob": { 466 | "version": "4.0.1", 467 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 468 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 469 | "dev": true, 470 | "requires": { 471 | "is-extglob": "^2.1.1" 472 | } 473 | }, 474 | "is-number": { 475 | "version": "7.0.0", 476 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 477 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 478 | "dev": true 479 | }, 480 | "is-regex": { 481 | "version": "1.0.5", 482 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", 483 | "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", 484 | "dev": true, 485 | "requires": { 486 | "has": "^1.0.3" 487 | } 488 | }, 489 | "is-symbol": { 490 | "version": "1.0.3", 491 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 492 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 493 | "dev": true, 494 | "requires": { 495 | "has-symbols": "^1.0.1" 496 | } 497 | }, 498 | "isexe": { 499 | "version": "2.0.0", 500 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 501 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 502 | "dev": true 503 | }, 504 | "js-yaml": { 505 | "version": "3.13.1", 506 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 507 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 508 | "dev": true, 509 | "requires": { 510 | "argparse": "^1.0.7", 511 | "esprima": "^4.0.0" 512 | } 513 | }, 514 | "locate-path": { 515 | "version": "3.0.0", 516 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 517 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 518 | "dev": true, 519 | "requires": { 520 | "p-locate": "^3.0.0", 521 | "path-exists": "^3.0.0" 522 | }, 523 | "dependencies": { 524 | "path-exists": { 525 | "version": "3.0.0", 526 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 527 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 528 | "dev": true 529 | } 530 | } 531 | }, 532 | "lodash": { 533 | "version": "4.17.15", 534 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 535 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", 536 | "dev": true 537 | }, 538 | "log-symbols": { 539 | "version": "3.0.0", 540 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", 541 | "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", 542 | "dev": true, 543 | "requires": { 544 | "chalk": "^2.4.2" 545 | } 546 | }, 547 | "make-error": { 548 | "version": "1.3.6", 549 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 550 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 551 | "dev": true 552 | }, 553 | "minimatch": { 554 | "version": "3.0.4", 555 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 556 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 557 | "dev": true, 558 | "requires": { 559 | "brace-expansion": "^1.1.7" 560 | } 561 | }, 562 | "minimist": { 563 | "version": "1.2.5", 564 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 565 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 566 | "dev": true 567 | }, 568 | "mkdirp": { 569 | "version": "0.5.5", 570 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 571 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 572 | "dev": true, 573 | "requires": { 574 | "minimist": "^1.2.5" 575 | } 576 | }, 577 | "mocha": { 578 | "version": "7.1.2", 579 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", 580 | "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", 581 | "dev": true, 582 | "requires": { 583 | "ansi-colors": "3.2.3", 584 | "browser-stdout": "1.3.1", 585 | "chokidar": "3.3.0", 586 | "debug": "3.2.6", 587 | "diff": "3.5.0", 588 | "escape-string-regexp": "1.0.5", 589 | "find-up": "3.0.0", 590 | "glob": "7.1.3", 591 | "growl": "1.10.5", 592 | "he": "1.2.0", 593 | "js-yaml": "3.13.1", 594 | "log-symbols": "3.0.0", 595 | "minimatch": "3.0.4", 596 | "mkdirp": "0.5.5", 597 | "ms": "2.1.1", 598 | "node-environment-flags": "1.0.6", 599 | "object.assign": "4.1.0", 600 | "strip-json-comments": "2.0.1", 601 | "supports-color": "6.0.0", 602 | "which": "1.3.1", 603 | "wide-align": "1.1.3", 604 | "yargs": "13.3.2", 605 | "yargs-parser": "13.1.2", 606 | "yargs-unparser": "1.6.0" 607 | }, 608 | "dependencies": { 609 | "find-up": { 610 | "version": "3.0.0", 611 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 612 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 613 | "dev": true, 614 | "requires": { 615 | "locate-path": "^3.0.0" 616 | } 617 | }, 618 | "glob": { 619 | "version": "7.1.3", 620 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 621 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 622 | "dev": true, 623 | "requires": { 624 | "fs.realpath": "^1.0.0", 625 | "inflight": "^1.0.4", 626 | "inherits": "2", 627 | "minimatch": "^3.0.4", 628 | "once": "^1.3.0", 629 | "path-is-absolute": "^1.0.0" 630 | } 631 | } 632 | } 633 | }, 634 | "ms": { 635 | "version": "2.1.1", 636 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 637 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 638 | "dev": true 639 | }, 640 | "node-environment-flags": { 641 | "version": "1.0.6", 642 | "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", 643 | "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", 644 | "dev": true, 645 | "requires": { 646 | "object.getownpropertydescriptors": "^2.0.3", 647 | "semver": "^5.7.0" 648 | } 649 | }, 650 | "normalize-path": { 651 | "version": "3.0.0", 652 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 653 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 654 | "dev": true 655 | }, 656 | "object-inspect": { 657 | "version": "1.7.0", 658 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", 659 | "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", 660 | "dev": true 661 | }, 662 | "object-keys": { 663 | "version": "1.1.1", 664 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 665 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 666 | "dev": true 667 | }, 668 | "object.assign": { 669 | "version": "4.1.0", 670 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 671 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 672 | "dev": true, 673 | "requires": { 674 | "define-properties": "^1.1.2", 675 | "function-bind": "^1.1.1", 676 | "has-symbols": "^1.0.0", 677 | "object-keys": "^1.0.11" 678 | } 679 | }, 680 | "object.getownpropertydescriptors": { 681 | "version": "2.1.0", 682 | "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", 683 | "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", 684 | "dev": true, 685 | "requires": { 686 | "define-properties": "^1.1.3", 687 | "es-abstract": "^1.17.0-next.1" 688 | } 689 | }, 690 | "once": { 691 | "version": "1.4.0", 692 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 693 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 694 | "dev": true, 695 | "requires": { 696 | "wrappy": "1" 697 | } 698 | }, 699 | "p-limit": { 700 | "version": "2.3.0", 701 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 702 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 703 | "dev": true, 704 | "requires": { 705 | "p-try": "^2.0.0" 706 | } 707 | }, 708 | "p-locate": { 709 | "version": "3.0.0", 710 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 711 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 712 | "dev": true, 713 | "requires": { 714 | "p-limit": "^2.0.0" 715 | } 716 | }, 717 | "p-try": { 718 | "version": "2.2.0", 719 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 720 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 721 | "dev": true 722 | }, 723 | "path-is-absolute": { 724 | "version": "1.0.1", 725 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 726 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 727 | "dev": true 728 | }, 729 | "pathval": { 730 | "version": "1.1.0", 731 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 732 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 733 | "dev": true 734 | }, 735 | "picomatch": { 736 | "version": "2.2.2", 737 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 738 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 739 | "dev": true 740 | }, 741 | "readdirp": { 742 | "version": "3.2.0", 743 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", 744 | "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", 745 | "dev": true, 746 | "requires": { 747 | "picomatch": "^2.0.4" 748 | } 749 | }, 750 | "require-directory": { 751 | "version": "2.1.1", 752 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 753 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 754 | "dev": true 755 | }, 756 | "require-main-filename": { 757 | "version": "2.0.0", 758 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", 759 | "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", 760 | "dev": true 761 | }, 762 | "semver": { 763 | "version": "5.7.1", 764 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 765 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 766 | "dev": true 767 | }, 768 | "set-blocking": { 769 | "version": "2.0.0", 770 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 771 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 772 | "dev": true 773 | }, 774 | "source-map": { 775 | "version": "0.6.1", 776 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 777 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 778 | "dev": true 779 | }, 780 | "source-map-support": { 781 | "version": "0.5.19", 782 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 783 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 784 | "dev": true, 785 | "requires": { 786 | "buffer-from": "^1.0.0", 787 | "source-map": "^0.6.0" 788 | } 789 | }, 790 | "sprintf-js": { 791 | "version": "1.0.3", 792 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 793 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 794 | "dev": true 795 | }, 796 | "string-width": { 797 | "version": "2.1.1", 798 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 799 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 800 | "dev": true, 801 | "requires": { 802 | "is-fullwidth-code-point": "^2.0.0", 803 | "strip-ansi": "^4.0.0" 804 | } 805 | }, 806 | "string.prototype.trimend": { 807 | "version": "1.0.1", 808 | "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", 809 | "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", 810 | "dev": true, 811 | "requires": { 812 | "define-properties": "^1.1.3", 813 | "es-abstract": "^1.17.5" 814 | } 815 | }, 816 | "string.prototype.trimleft": { 817 | "version": "2.1.2", 818 | "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", 819 | "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", 820 | "dev": true, 821 | "requires": { 822 | "define-properties": "^1.1.3", 823 | "es-abstract": "^1.17.5", 824 | "string.prototype.trimstart": "^1.0.0" 825 | } 826 | }, 827 | "string.prototype.trimright": { 828 | "version": "2.1.2", 829 | "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", 830 | "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", 831 | "dev": true, 832 | "requires": { 833 | "define-properties": "^1.1.3", 834 | "es-abstract": "^1.17.5", 835 | "string.prototype.trimend": "^1.0.0" 836 | } 837 | }, 838 | "string.prototype.trimstart": { 839 | "version": "1.0.1", 840 | "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 841 | "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", 842 | "dev": true, 843 | "requires": { 844 | "define-properties": "^1.1.3", 845 | "es-abstract": "^1.17.5" 846 | } 847 | }, 848 | "strip-ansi": { 849 | "version": "4.0.0", 850 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 851 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 852 | "dev": true, 853 | "requires": { 854 | "ansi-regex": "^3.0.0" 855 | } 856 | }, 857 | "strip-json-comments": { 858 | "version": "2.0.1", 859 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 860 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 861 | "dev": true 862 | }, 863 | "supports-color": { 864 | "version": "6.0.0", 865 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", 866 | "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", 867 | "dev": true, 868 | "requires": { 869 | "has-flag": "^3.0.0" 870 | } 871 | }, 872 | "to-regex-range": { 873 | "version": "5.0.1", 874 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 875 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 876 | "dev": true, 877 | "requires": { 878 | "is-number": "^7.0.0" 879 | } 880 | }, 881 | "ts-node": { 882 | "version": "8.10.1", 883 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", 884 | "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", 885 | "dev": true, 886 | "requires": { 887 | "arg": "^4.1.0", 888 | "diff": "^4.0.1", 889 | "make-error": "^1.1.1", 890 | "source-map-support": "^0.5.17", 891 | "yn": "3.1.1" 892 | }, 893 | "dependencies": { 894 | "diff": { 895 | "version": "4.0.2", 896 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 897 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 898 | "dev": true 899 | } 900 | } 901 | }, 902 | "type-detect": { 903 | "version": "4.0.8", 904 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 905 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 906 | "dev": true 907 | }, 908 | "typescript": { 909 | "version": "3.8.3", 910 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", 911 | "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==" 912 | }, 913 | "which": { 914 | "version": "1.3.1", 915 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 916 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 917 | "dev": true, 918 | "requires": { 919 | "isexe": "^2.0.0" 920 | } 921 | }, 922 | "which-module": { 923 | "version": "2.0.0", 924 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 925 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 926 | "dev": true 927 | }, 928 | "wide-align": { 929 | "version": "1.1.3", 930 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 931 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 932 | "dev": true, 933 | "requires": { 934 | "string-width": "^1.0.2 || 2" 935 | } 936 | }, 937 | "wrap-ansi": { 938 | "version": "5.1.0", 939 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 940 | "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", 941 | "dev": true, 942 | "requires": { 943 | "ansi-styles": "^3.2.0", 944 | "string-width": "^3.0.0", 945 | "strip-ansi": "^5.0.0" 946 | }, 947 | "dependencies": { 948 | "ansi-regex": { 949 | "version": "4.1.0", 950 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 951 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 952 | "dev": true 953 | }, 954 | "string-width": { 955 | "version": "3.1.0", 956 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 957 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 958 | "dev": true, 959 | "requires": { 960 | "emoji-regex": "^7.0.1", 961 | "is-fullwidth-code-point": "^2.0.0", 962 | "strip-ansi": "^5.1.0" 963 | } 964 | }, 965 | "strip-ansi": { 966 | "version": "5.2.0", 967 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 968 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 969 | "dev": true, 970 | "requires": { 971 | "ansi-regex": "^4.1.0" 972 | } 973 | } 974 | } 975 | }, 976 | "wrappy": { 977 | "version": "1.0.2", 978 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 979 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 980 | "dev": true 981 | }, 982 | "y18n": { 983 | "version": "4.0.0", 984 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 985 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", 986 | "dev": true 987 | }, 988 | "yargs": { 989 | "version": "13.3.2", 990 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", 991 | "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", 992 | "dev": true, 993 | "requires": { 994 | "cliui": "^5.0.0", 995 | "find-up": "^3.0.0", 996 | "get-caller-file": "^2.0.1", 997 | "require-directory": "^2.1.1", 998 | "require-main-filename": "^2.0.0", 999 | "set-blocking": "^2.0.0", 1000 | "string-width": "^3.0.0", 1001 | "which-module": "^2.0.0", 1002 | "y18n": "^4.0.0", 1003 | "yargs-parser": "^13.1.2" 1004 | }, 1005 | "dependencies": { 1006 | "ansi-regex": { 1007 | "version": "4.1.0", 1008 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1009 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1010 | "dev": true 1011 | }, 1012 | "find-up": { 1013 | "version": "3.0.0", 1014 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 1015 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 1016 | "dev": true, 1017 | "requires": { 1018 | "locate-path": "^3.0.0" 1019 | } 1020 | }, 1021 | "string-width": { 1022 | "version": "3.1.0", 1023 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1024 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1025 | "dev": true, 1026 | "requires": { 1027 | "emoji-regex": "^7.0.1", 1028 | "is-fullwidth-code-point": "^2.0.0", 1029 | "strip-ansi": "^5.1.0" 1030 | } 1031 | }, 1032 | "strip-ansi": { 1033 | "version": "5.2.0", 1034 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1035 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1036 | "dev": true, 1037 | "requires": { 1038 | "ansi-regex": "^4.1.0" 1039 | } 1040 | } 1041 | } 1042 | }, 1043 | "yargs-parser": { 1044 | "version": "13.1.2", 1045 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", 1046 | "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", 1047 | "dev": true, 1048 | "requires": { 1049 | "camelcase": "^5.0.0", 1050 | "decamelize": "^1.2.0" 1051 | }, 1052 | "dependencies": { 1053 | "camelcase": { 1054 | "version": "5.3.1", 1055 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", 1056 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", 1057 | "dev": true 1058 | } 1059 | } 1060 | }, 1061 | "yargs-unparser": { 1062 | "version": "1.6.0", 1063 | "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", 1064 | "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", 1065 | "dev": true, 1066 | "requires": { 1067 | "flat": "^4.1.0", 1068 | "lodash": "^4.17.15", 1069 | "yargs": "^13.3.0" 1070 | } 1071 | }, 1072 | "yn": { 1073 | "version": "3.1.1", 1074 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1075 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1076 | "dev": true 1077 | } 1078 | } 1079 | } 1080 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "patrones", 3 | "version": "1.0.0", 4 | "description": "Patrones de diseño con TypeScript", 5 | "scripts": { 6 | "test-singleton": "mocha -r ts-node/register creational/singleton/*.spec.ts", 7 | "test-factory": "mocha -r ts-node/register creational/factory/*.spec.ts", 8 | "test-abstract-factory": "mocha -r ts-node/register creational/abstract-factory/*.spec.ts", 9 | "test-adapter": "mocha -r ts-node/register structural/adapter/*.spec.ts", 10 | "test-decorator": "mocha -r ts-node/register structural/decorator/*.spec.ts", 11 | "test-proxy": "mocha -r ts-node/register structural/proxy/*.spec.ts", 12 | "test-command": "mocha -r ts-node/register behaviour/command/*.spec.ts", 13 | "test-observer": "mocha -r ts-node/register behaviour/observer/*.spec.ts", 14 | "test-strategy": "mocha -r ts-node/register behaviour/strategy/*.spec.ts" 15 | }, 16 | "author": "kodoti", 17 | "license": "ISC", 18 | "dependencies": { 19 | "typescript": "^3.8.3" 20 | }, 21 | "devDependencies": { 22 | "@types/chai": "^4.2.11", 23 | "@types/mocha": "^7.0.2", 24 | "chai": "^4.2.0", 25 | "mocha": "^7.1.2", 26 | "ts-node": "^8.10.1" 27 | } 28 | } -------------------------------------------------------------------------------- /structural/adapter/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import FacebookNotification from "./src/providers/facebook-notification"; 4 | import SlackNotification from "./src/providers/slack-notification"; 5 | 6 | const providers: any[] = [ 7 | new FacebookNotification(), 8 | new SlackNotification() 9 | ]; 10 | 11 | describe("INotification", () => { 12 | it("Are providers compatible?", () => { 13 | providers.forEach(p => { 14 | assert.typeOf(p.post, 'function'); 15 | }); 16 | }); 17 | }); -------------------------------------------------------------------------------- /structural/adapter/index.ts: -------------------------------------------------------------------------------- 1 | import NotificationService from "./src/services/notification.service"; 2 | import INotification from "./src/providers/notification.interface"; 3 | import FacebookNotification from "./src/providers/facebook-notification"; 4 | import SlackAdapterNotification from "./src/providers/slack-adapter-notification"; 5 | import SlackNotification from "./src/providers/slack-notification"; 6 | 7 | const providers: INotification[] = [ 8 | new FacebookNotification(), 9 | new SlackAdapterNotification( 10 | new SlackNotification() 11 | ) 12 | ]; 13 | 14 | const notificationService = new NotificationService(providers); 15 | notificationService.post("Nuevo curso", "25% descuentos a los 10 primeros en inscribirse."); -------------------------------------------------------------------------------- /structural/adapter/src/providers/facebook-notification.ts: -------------------------------------------------------------------------------- 1 | import INotification from "./notification.interface"; 2 | 3 | class FacebookNotification implements INotification { 4 | public post(title: string, message: string): void { 5 | console.log(`Sending ${title} - ${message} - Facebook`); 6 | } 7 | } 8 | 9 | export default FacebookNotification; -------------------------------------------------------------------------------- /structural/adapter/src/providers/notification.interface.ts: -------------------------------------------------------------------------------- 1 | export default interface INotification { 2 | post(title: string, message: string): void; 3 | } -------------------------------------------------------------------------------- /structural/adapter/src/providers/slack-adapter-notification.ts: -------------------------------------------------------------------------------- 1 | import INotification from "./notification.interface"; 2 | import SlackNotification from "./slack-notification"; 3 | 4 | class SlackAdapterNotification implements INotification { 5 | constructor(private slackNotification: SlackNotification) { } 6 | 7 | public post(title: string, message: string): void { 8 | this.slackNotification.send("general", title, message); 9 | } 10 | } 11 | 12 | export default SlackAdapterNotification; -------------------------------------------------------------------------------- /structural/adapter/src/providers/slack-notification.ts: -------------------------------------------------------------------------------- 1 | class SlackNotification { 2 | public send(channelId: string, title: string, message: string): void { 3 | console.log(`Sending ${title} - ${message} to ${channelId} - Slack`); 4 | } 5 | } 6 | 7 | export default SlackNotification; -------------------------------------------------------------------------------- /structural/adapter/src/services/notification.service.ts: -------------------------------------------------------------------------------- 1 | import INotification from "../providers/notification.interface"; 2 | 3 | class NotificationService { 4 | constructor(private providers: INotification[]) { } 5 | 6 | public post(title: string, message: string): void { 7 | this.providers.forEach(p => { 8 | p.post(title, message); 9 | }); 10 | } 11 | } 12 | 13 | export default NotificationService; -------------------------------------------------------------------------------- /structural/decorator/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Product } from "./src/product"; 4 | import { BasePrice } from "./src/base-price"; 5 | import { SpecialPriceDecorator } from "./src/decorators/special-price.decorator"; 6 | import { VipCustomerDecorator } from "./src/decorators/vip-customer.decorator"; 7 | 8 | describe("Product price", () => { 9 | it("base price", () => { 10 | const product = new Product("Guitara Suhr Classic", 2500); 11 | 12 | let specialPrice = new BasePrice(); 13 | 14 | product.setSpecialPrice( 15 | specialPrice.calculate(product.price)); 16 | 17 | assert.isTrue(product.specialPrice === 0); 18 | }); 19 | 20 | it("special price discount", () => { 21 | const product = new Product("Guitara Suhr Classic", 2500); 22 | 23 | let specialPrice = new BasePrice(); 24 | 25 | specialPrice = new SpecialPriceDecorator(specialPrice); 26 | 27 | product.setSpecialPrice( 28 | specialPrice.calculate(product.price)); 29 | 30 | assert.isTrue(product.price > product.specialPrice); 31 | }); 32 | 33 | it("vip customer discount", () => { 34 | const product = new Product("Guitara Suhr Classic", 2500); 35 | 36 | let specialPrice = new BasePrice(); 37 | 38 | specialPrice = new VipCustomerDecorator(specialPrice); 39 | 40 | product.setSpecialPrice( 41 | specialPrice.calculate(product.price)); 42 | 43 | assert.isTrue(product.price > product.specialPrice); 44 | }); 45 | 46 | it("special price and vip customer discount", () => { 47 | const product = new Product("Guitara Suhr Classic", 2500); 48 | 49 | let specialPrice = new BasePrice(); 50 | 51 | specialPrice = new SpecialPriceDecorator(specialPrice); 52 | specialPrice = new VipCustomerDecorator(specialPrice); 53 | 54 | product.setSpecialPrice( 55 | specialPrice.calculate(product.price)); 56 | 57 | assert.isTrue(product.price > product.specialPrice); 58 | }); 59 | }); -------------------------------------------------------------------------------- /structural/decorator/index.ts: -------------------------------------------------------------------------------- 1 | import { Customer } from "./src/customer"; 2 | import { Product } from "./src/product"; 3 | import { BasePrice } from "./src/base-price"; 4 | import { SpecialPriceDecorator } from "./src/decorators/special-price.decorator"; 5 | import { VipCustomerDecorator } from "./src/decorators/vip-customer.decorator"; 6 | 7 | const customer = new Customer("Eduardo", true, "VIP"); 8 | const product = new Product("Guitara Suhr Classic", 2500); 9 | 10 | let discount = new BasePrice(); 11 | 12 | if (customer.isFirstBuy) { 13 | discount = new SpecialPriceDecorator(discount); 14 | } 15 | 16 | if (customer.type === 'VIP') { 17 | discount = new VipCustomerDecorator(discount); 18 | } 19 | 20 | product.setSpecialPrice( 21 | discount.calculate(product.price)); 22 | 23 | console.log(product); -------------------------------------------------------------------------------- /structural/decorator/src/base-price.ts: -------------------------------------------------------------------------------- 1 | import { IDiscount } from "./interfaces/discount.interface"; 2 | 3 | export class BasePrice implements IDiscount { 4 | calculate(input: number): number { 5 | console.log(`${this.constructor.name} discount applied.`); 6 | return input; 7 | } 8 | } -------------------------------------------------------------------------------- /structural/decorator/src/customer.ts: -------------------------------------------------------------------------------- 1 | export class Customer { 2 | constructor( 3 | public name: string, 4 | public isFirstBuy: boolean, 5 | public type: string 6 | ) { } 7 | } -------------------------------------------------------------------------------- /structural/decorator/src/decorators/special-price.decorator.ts: -------------------------------------------------------------------------------- 1 | import { IDiscount } from "../interfaces/discount.interface"; 2 | 3 | export class SpecialPriceDecorator implements IDiscount { 4 | constructor(private readonly decorator: IDiscount) { } 5 | 6 | private readonly discountAmount: number = 0.04; 7 | 8 | calculate(input: number): number { 9 | console.log(`${this.constructor.name} discount applied.`); 10 | 11 | input = (input * (1 - this.discountAmount)); 12 | 13 | return this.decorator.calculate(input); 14 | } 15 | } -------------------------------------------------------------------------------- /structural/decorator/src/decorators/vip-customer.decorator.ts: -------------------------------------------------------------------------------- 1 | import { IDiscount } from "../interfaces/discount.interface"; 2 | 3 | export class VipCustomerDecorator implements IDiscount { 4 | constructor(private readonly decorator: IDiscount) { } 5 | 6 | private readonly discountAmount: number = 0.02; 7 | 8 | calculate(input: number): number { 9 | console.log(`${this.constructor.name} discount applied.`); 10 | 11 | input = (input * (1 - this.discountAmount)); 12 | 13 | return this.decorator.calculate(input); 14 | } 15 | } -------------------------------------------------------------------------------- /structural/decorator/src/interfaces/discount.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IDiscount { 2 | calculate(input: number): number; 3 | } -------------------------------------------------------------------------------- /structural/decorator/src/product.ts: -------------------------------------------------------------------------------- 1 | export class Product { 2 | public specialPrice: number = 0; 3 | public discount: number = 0; 4 | 5 | constructor( 6 | public name: string, 7 | public price: number 8 | ) { } 9 | 10 | setSpecialPrice(input: number) { 11 | if (this.price > input) { 12 | this.specialPrice = input; 13 | this.discount = 1 - this.specialPrice / this.price; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /structural/proxy/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { VideoProxy } from "./src/video.proxy"; 4 | import { YouTubeApi } from "./src/youtube.api"; 5 | 6 | const proxy = new VideoProxy(new YouTubeApi()); 7 | 8 | describe("Video proxy", function () { 9 | this.timeout(0); 10 | 11 | it("was cached?", async () => { 12 | const key = 'courses'; 13 | 14 | let result = await proxy.getPlayList(key); 15 | result = await proxy.getPlayList(key); 16 | 17 | assert.isDefined(proxy['cache'][key]); 18 | }); 19 | }); -------------------------------------------------------------------------------- /structural/proxy/index.ts: -------------------------------------------------------------------------------- 1 | import { VideoProxy } from "./src/video.proxy"; 2 | import { YouTubeApi } from "./src/youtube.api"; 3 | 4 | const proxy = new VideoProxy(new YouTubeApi()); 5 | 6 | (async () => { 7 | // first time 8 | await getPlayList(); 9 | 10 | // second time (cache) 11 | await getPlayList(); 12 | })(); 13 | 14 | async function getPlayList() { 15 | const startDate = new Date(); 16 | 17 | await proxy.getPlayList('courses'); 18 | 19 | const endDate = new Date(); 20 | 21 | console.log(`Process completed on ${(endDate.getTime() - startDate.getTime()) / 1000} seconds`) 22 | } -------------------------------------------------------------------------------- /structural/proxy/src/video-provider.interface.ts: -------------------------------------------------------------------------------- 1 | interface IVideoProvider { 2 | getPlayList(code: string): Promise; 3 | } 4 | 5 | export { 6 | IVideoProvider 7 | }; -------------------------------------------------------------------------------- /structural/proxy/src/video.proxy.ts: -------------------------------------------------------------------------------- 1 | import { IVideoProvider } from "./video-provider.interface"; 2 | 3 | class VideoProxy implements IVideoProvider { 4 | private cache: any = {}; 5 | 6 | constructor(private readonly provider: IVideoProvider) { } 7 | 8 | async getPlayList(code: string): Promise { 9 | let result = this.cache[code]; 10 | 11 | if (!result) { 12 | result = await this.provider.getPlayList(code); 13 | 14 | // push to cache 15 | this.cache[code] = result; 16 | } 17 | 18 | return result; 19 | } 20 | } 21 | 22 | export { 23 | VideoProxy 24 | }; -------------------------------------------------------------------------------- /structural/proxy/src/youtube.api.ts: -------------------------------------------------------------------------------- 1 | import { IVideoProvider } from "./video-provider.interface"; 2 | 3 | class YouTubeApi implements IVideoProvider { 4 | private playList: any = { 5 | courses: [ 6 | 'https://www.youtube.com/watch?v=DKNVMILZDks', 7 | 'https://www.youtube.com/watch?v=Ph4SLROqSEQ', 8 | 'https://www.youtube.com/watch?v=Tvs3r0TVcRI' 9 | ] 10 | }; 11 | 12 | async getPlayList(code: string): Promise { 13 | return new Promise((resolve, reject) => { 14 | setTimeout(() => { 15 | const result = this.playList[code] || null; 16 | resolve(result); 17 | }, 3000); 18 | }); 19 | } 20 | } 21 | 22 | export { 23 | YouTubeApi 24 | }; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "ESNext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 6 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | // "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | "outDir": "./dist", /* Redirect output structure to the directory. */ 16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | /* Strict Type-Checking Options */ 25 | "strict": true, /* Enable all strict type-checking options. */ 26 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 27 | // "strictNullChecks": true, /* Enable strict null checks. */ 28 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 29 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 30 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 31 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 32 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 33 | /* Additional Checks */ 34 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 35 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 36 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 37 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 38 | /* Module Resolution Options */ 39 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 40 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 41 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 42 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 43 | // "typeRoots": [], /* List of folders to include type definitions from. */ 44 | // "types": [], /* Type declaration files to be included in compilation. */ 45 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 46 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 47 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 48 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 49 | /* Source Map Options */ 50 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 51 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 52 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 53 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 54 | /* Experimental Options */ 55 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 56 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 57 | /* Advanced Options */ 58 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, 59 | "resolveJsonModule": true 60 | } 61 | } --------------------------------------------------------------------------------