├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── LICENSE ├── README.md ├── VERSION ├── bin ├── cjs │ ├── core │ │ ├── Controller.js │ │ ├── Model.js │ │ └── View.js │ ├── index.js │ ├── package.json │ └── patterns │ │ ├── command │ │ ├── MacroCommand.js │ │ └── SimpleCommand.js │ │ ├── facade │ │ └── Facade.js │ │ ├── mediator │ │ └── Mediator.js │ │ ├── observer │ │ ├── Notification.js │ │ ├── Notifier.js │ │ └── Observer.js │ │ └── proxy │ │ └── Proxy.js ├── esm │ ├── core │ │ ├── Controller.js │ │ ├── Model.js │ │ └── View.js │ ├── index.js │ ├── package.json │ └── patterns │ │ ├── command │ │ ├── MacroCommand.js │ │ └── SimpleCommand.js │ │ ├── facade │ │ └── Facade.js │ │ ├── mediator │ │ └── Mediator.js │ │ ├── observer │ │ ├── Notification.js │ │ ├── Notifier.js │ │ └── Observer.js │ │ └── proxy │ │ └── Proxy.js └── types │ ├── core │ ├── Controller.d.ts │ ├── Model.d.ts │ └── View.d.ts │ ├── index.d.ts │ ├── interfaces │ ├── ICommand.d.ts │ ├── IController.d.ts │ ├── IFacade.d.ts │ ├── IMediator.d.ts │ ├── IModel.d.ts │ ├── INotification.d.ts │ ├── INotifier.d.ts │ ├── IObserver.d.ts │ ├── IProxy.d.ts │ └── IView.d.ts │ └── patterns │ ├── command │ ├── MacroCommand.d.ts │ └── SimpleCommand.d.ts │ ├── facade │ └── Facade.d.ts │ ├── mediator │ └── Mediator.d.ts │ ├── observer │ ├── Notification.d.ts │ ├── Notifier.d.ts │ └── Observer.d.ts │ └── proxy │ └── Proxy.d.ts ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── icons.js │ ├── icons.svg │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── classes │ ├── Controller.html │ ├── Facade.html │ ├── MacroCommand.html │ ├── Mediator.html │ ├── Model.html │ ├── Notification.html │ ├── Notifier.html │ ├── Observer.html │ ├── Proxy.html │ ├── SimpleCommand.html │ └── View.html ├── hierarchy.html ├── index.html ├── interfaces │ ├── ICommand.html │ ├── IController.html │ ├── IFacade.html │ ├── IMediator.html │ ├── IModel.html │ ├── INotification.html │ ├── INotifier.html │ ├── IObserver.html │ ├── IProxy.html │ └── IView.html └── modules.html ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── core │ ├── Controller.ts │ ├── Model.ts │ └── View.ts ├── index.ts ├── interfaces │ ├── ICommand.ts │ ├── IController.ts │ ├── IFacade.ts │ ├── IMediator.ts │ ├── IModel.ts │ ├── INotification.ts │ ├── INotifier.ts │ ├── IObserver.ts │ ├── IProxy.ts │ └── IView.ts └── patterns │ ├── command │ ├── MacroCommand.ts │ └── SimpleCommand.ts │ ├── facade │ └── Facade.ts │ ├── mediator │ └── Mediator.ts │ ├── observer │ ├── Notification.ts │ ├── Notifier.ts │ └── Observer.ts │ └── proxy │ └── Proxy.ts ├── test ├── core │ ├── Controller.spec.ts │ ├── ControllerTestCommand.ts │ ├── ControllerTestCommand2.ts │ ├── ControllerTestVO.ts │ ├── Model.spec.ts │ ├── ModelTestProxy.ts │ ├── View.spec.ts │ ├── ViewTestMediator.ts │ ├── ViewTestMediator2.ts │ ├── ViewTestMediator3.ts │ ├── ViewTestMediator4.ts │ ├── ViewTestMediator5.ts │ ├── ViewTestMediator6.ts │ └── ViewTestNote.ts └── patterns │ ├── command │ ├── MacroCommand.spec.ts │ ├── MacroCommandTestVO.ts │ ├── SimpleCommand.spec.ts │ ├── SimpleCommandTestCommand.ts │ └── SimpleCommandTestVO.ts │ ├── facade │ ├── Facade.spec.ts │ ├── FacadeTestCommand.ts │ └── FacadeTestVO.ts │ ├── mediator │ └── Mediator.spec.ts │ ├── observer │ ├── Notification.spec.ts │ ├── Notifier.spec.ts │ └── Observer.spec.ts │ └── proxy │ └── Proxy.spec.ts └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es2021": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "overrides": [ 12 | { 13 | "env": { 14 | "node": true 15 | }, 16 | "files": [ 17 | ".eslintrc.{js,cjs}" 18 | ], 19 | "parserOptions": { 20 | "sourceType": "script" 21 | } 22 | } 23 | ], 24 | "parser": "@typescript-eslint/parser", 25 | "parserOptions": { 26 | "ecmaVersion": "latest" 27 | }, 28 | "plugins": [ 29 | "@typescript-eslint" 30 | ], 31 | "rules": { 32 | "@typescript-eslint/no-explicit-any": "off", 33 | "indent": [ 34 | "error", 35 | 4 36 | ], 37 | "linebreak-style": [ 38 | "error", 39 | "unix" 40 | ], 41 | "quotes": [ 42 | "error", 43 | "double" 44 | ], 45 | "semi": [ 46 | "error", 47 | "always" 48 | ] 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | bin/** linguist-vendored 2 | *.js linguist-vendored -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [20.x, 21.x, 22.x] 19 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | cache: 'npm' 28 | - run: npm ci 29 | - run: npm run build --if-present 30 | - run: npm test 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | coverage 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2025, Saad Shams 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [PureMVC](http://puremvc.org/) TypeScript MultiCore Framework [![Node.js CI](https://github.com/PureMVC/puremvc-typescript-multicore-framework/actions/workflows/node.js.yml/badge.svg)](https://github.com/PureMVC/puremvc-typescript-multicore-framework/actions/workflows/node.js.yml) 2 | 3 | PureMVC is a lightweight framework for creating applications based upon the classic [Model-View-Controller](http://en.wikipedia.org/wiki/Model-view-controller) design meta-pattern. It supports [modular programming](http://en.wikipedia.org/wiki/Modular_programming) through the use of [Multiton](http://en.wikipedia.org/wiki/Multiton) Core actors instead of the [Singletons](http://en.wikipedia.org/wiki/Singleton_pattern). 4 | 5 | ## Installation 6 | ```shell 7 | npm install @puremvc/puremvc-typescript-multicore-framework 8 | ``` 9 | 10 | ## Documentation 11 | * [API Docs](https://puremvc.org/pages/docs/TypeScript/multicore/) 12 | * [Legacy Implementation](https://github.com/PureMVC/puremvc-typescript-multicore-framework/tree/1.3) 13 | 14 | ## Ported Framework 15 | * This is a direct port of the original [AS3 MultiCore Framework](https://github.com/PureMVC/puremvc-as3-multicore-framework) 16 | 17 | ## Demos 18 | * [Basic Employee Admin](https://github.com/PureMVC/puremvc-typescript-demo-employeeadmin) 19 | 20 | ## Utilities 21 | * [Async Command](https://github.com/PureMVC/puremvc-typescript-util-async-command) 22 | * [State Machine](https://github.com/PureMVC/puremvc-typescript-util-state-machine) 23 | * [Pipes](https://github.com/PureMVC/puremvc-typescript-util-pipes) 24 | 25 | ## Platforms / Technologies 26 | * [TypeScript](https://typescriptlang.org) 27 | * [Node.js](https://nodejs.org) 28 | * [NPM](https://www.npmjs.com/package/@puremvc/puremvc-typescript-multicore-framework?activeTab=readme) 29 | 30 | ## License 31 | * PureMVC MultiCore Framework for TypeScript - Copyright © 2025 [Saad Shams](https://www.linkedin.com/in/muizz), [Cliff Hall](https://www.linkedin.com/in/cliffhall) 32 | * PureMVC - Copyright © 2025 [Futurescale, Inc.](http://futurescale.com/) 33 | * All rights reserved. 34 | 35 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 36 | 37 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 38 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 39 | * Neither the name of Futurescale, Inc., PureMVC.org, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 40 | 41 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | PureMVC MultiCore Framework for TypeScript 2 | -------------------------------------------------------------------------- 3 | Release Date: 4/22/25 4 | Platform: TypeScript 5 | Version: 2 6 | Revision: 1 7 | Minor: 2 8 | Authors: Saad Shams 9 | : Cliff Hall 10 | -------------------------------------------------------------------------- 11 | 2.0.0 - Brand new implementation of ported code, equivalent to AS3 MultiCore Version 1.0.5. 12 | 2.0.1 - CI/CD Pipeline 13 | 2.0.2 - Updated docs and tests 14 | 2.0.3 - Unpublished 15 | 2.0.4 - Update IFacade (remove inherited sendNotification initializeNotifier methods) 16 | and Mediator (viewComponent type any, not Object) 17 | 2.0.5 - Fix package.json for importing types properly 18 | 2.0.6 - Add test coverage reporting 19 | 2.0.7 - Increase test coverage 20 | 2.0.8 - Remove auto-publish to npm. Remove interfaces folder from bin/cjs and bin/esm 21 | 2.0.9 - README demos and utils 22 | 2.1.0 - Final esm/cjs release with proper types. 23 | 2.1.1 - README Update 24 | 2.1.2 - Fix entrypoint 25 | -------------------------------------------------------------------------------- /bin/cjs/core/Model.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // Model.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Model = void 0; 11 | /** 12 | * A Multiton `Model` implementation. 13 | * 14 | * In PureMVC, the `Model` class provides 15 | * access to model objects (Proxies) by named lookup. 16 | * 17 | * The `Model` assumes these responsibilities: 18 | * 19 | * - Maintain a cache of `Proxy` instances. 20 | * - Provide methods for registering, retrieving, and removing 21 | * `Proxy` instances. 22 | * 23 | * Your application must register `Proxy` instances 24 | * with the `Model`. Typically, you use an 25 | * `Command` to create and register `Proxy` 26 | * instances once the `Facade` has initialized the Core 27 | * actors. 28 | * 29 | * @see {@link Proxy} 30 | * 31 | * @class Model 32 | */ 33 | class Model { 34 | /** 35 | * Constructor. 36 | * 37 | * This `Model` implementation is a Multiton, 38 | * so you should not call the constructor 39 | * directly, but instead call the static Multiton 40 | * Factory method `Model.getInstance(multitonKey)` 41 | * 42 | * @param {string} key 43 | * 44 | * @throws {Error} Error if instance for this Multiton key instance has already been constructed 45 | */ 46 | constructor(key) { 47 | if (Model.instanceMap[key] != null) 48 | throw Error(Model.MULTITON_MSG); 49 | this.multitonKey = key; 50 | Model.instanceMap[key] = this; 51 | this.proxyMap = {}; 52 | this.initializeModel(); 53 | } 54 | /** 55 | * Initialize the `Model` instance. 56 | * 57 | * Called automatically by the constructor, this 58 | * is your opportunity to initialize the Multiton 59 | * instance in your subclass without overriding the 60 | * constructor. 61 | * 62 | * @returns {void} 63 | */ 64 | initializeModel() { 65 | } 66 | /** 67 | * `Model` Multiton Factory method. 68 | * 69 | * @param {string} key - The key used to identify the model instance. 70 | * @param {(key: string) => IModel} factory - A factory function that creates a new instance of the model if one does not already exist for the specified key. 71 | * @returns {IModel} The model instance associated with the given key. 72 | */ 73 | static getInstance(key, factory) { 74 | if (Model.instanceMap[key] == null) 75 | Model.instanceMap[key] = factory(key); 76 | return Model.instanceMap[key]; 77 | } 78 | /** 79 | * Register a `Proxy` with the `Model`. 80 | * 81 | * @param {IProxy} proxy - The proxy instance to be registered. 82 | * @returns {void} 83 | */ 84 | registerProxy(proxy) { 85 | proxy.initializeNotifier(this.multitonKey); 86 | this.proxyMap[proxy.name] = proxy; 87 | proxy.onRegister(); 88 | } 89 | /** 90 | * Retrieve a `Proxy` from the `Model`. 91 | * 92 | * @param {string} proxyName - The name of the proxy to retrieve. 93 | * @returns {IProxy | null} The proxy instance associated with the given name, or `null` if no such proxy exists. 94 | */ 95 | retrieveProxy(proxyName) { 96 | return this.proxyMap[proxyName] || null; 97 | } 98 | /** 99 | * Check if a Proxy is registered 100 | * 101 | * @param {string} proxyName - The name of the proxy to check. 102 | * @returns {boolean} `true` if a proxy with the specified name is registered; otherwise, `false`. 103 | */ 104 | hasProxy(proxyName) { 105 | return this.proxyMap[proxyName] != null; 106 | } 107 | /** 108 | * Remove a `Proxy` from the `Model`. 109 | * 110 | * @param {string} proxyName - The name of the proxy to be removed. 111 | * @returns {IProxy | null} The removed proxy instance, or `null` if no proxy with the given name was found. 112 | */ 113 | removeProxy(proxyName) { 114 | const proxy = this.proxyMap[proxyName]; 115 | if (!proxy) 116 | return null; 117 | delete this.proxyMap[proxyName]; 118 | proxy.onRemove(); 119 | return proxy; 120 | } 121 | /** 122 | * Remove a Model instance 123 | * 124 | * @param {string} key - The key used to identify the model instance to be removed. 125 | * @returns {void} 126 | */ 127 | static removeModel(key) { 128 | delete Model.instanceMap[key]; 129 | } 130 | } 131 | exports.Model = Model; 132 | /** Message Constants 133 | * @type {string} */ 134 | Model.MULTITON_MSG = "Model instance for this Multiton key already constructed!"; 135 | /** Multiton Instances 136 | * @type {{ [key: string]: IModel }} */ 137 | Model.instanceMap = {}; 138 | -------------------------------------------------------------------------------- /bin/cjs/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // index.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Proxy = exports.Observer = exports.Notifier = exports.Notification = exports.Mediator = exports.Facade = exports.SimpleCommand = exports.MacroCommand = exports.View = exports.Model = exports.Controller = void 0; 11 | var Controller_1 = require("./core/Controller"); 12 | Object.defineProperty(exports, "Controller", { enumerable: true, get: function () { return Controller_1.Controller; } }); 13 | var Model_1 = require("./core/Model"); 14 | Object.defineProperty(exports, "Model", { enumerable: true, get: function () { return Model_1.Model; } }); 15 | var View_1 = require("./core/View"); 16 | Object.defineProperty(exports, "View", { enumerable: true, get: function () { return View_1.View; } }); 17 | var MacroCommand_1 = require("./patterns/command/MacroCommand"); 18 | Object.defineProperty(exports, "MacroCommand", { enumerable: true, get: function () { return MacroCommand_1.MacroCommand; } }); 19 | var SimpleCommand_1 = require("./patterns/command/SimpleCommand"); 20 | Object.defineProperty(exports, "SimpleCommand", { enumerable: true, get: function () { return SimpleCommand_1.SimpleCommand; } }); 21 | var Facade_1 = require("./patterns/facade/Facade"); 22 | Object.defineProperty(exports, "Facade", { enumerable: true, get: function () { return Facade_1.Facade; } }); 23 | var Mediator_1 = require("./patterns/mediator/Mediator"); 24 | Object.defineProperty(exports, "Mediator", { enumerable: true, get: function () { return Mediator_1.Mediator; } }); 25 | var Notification_1 = require("./patterns/observer/Notification"); 26 | Object.defineProperty(exports, "Notification", { enumerable: true, get: function () { return Notification_1.Notification; } }); 27 | var Notifier_1 = require("./patterns/observer/Notifier"); 28 | Object.defineProperty(exports, "Notifier", { enumerable: true, get: function () { return Notifier_1.Notifier; } }); 29 | var Observer_1 = require("./patterns/observer/Observer"); 30 | Object.defineProperty(exports, "Observer", { enumerable: true, get: function () { return Observer_1.Observer; } }); 31 | var Proxy_1 = require("./patterns/proxy/Proxy"); 32 | Object.defineProperty(exports, "Proxy", { enumerable: true, get: function () { return Proxy_1.Proxy; } }); 33 | -------------------------------------------------------------------------------- /bin/cjs/package.json: -------------------------------------------------------------------------------- 1 | {"type": "commonjs"} 2 | -------------------------------------------------------------------------------- /bin/cjs/patterns/command/MacroCommand.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // MacroCommand.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.MacroCommand = void 0; 11 | const SimpleCommand_1 = require("./SimpleCommand"); 12 | /** 13 | * A base `Command` implementation that executes other `Command`s. 14 | * 15 | * A `MacroCommand` maintains a list of 16 | * `Command` Class references called `SubCommands`. 17 | * 18 | * When `execute` is called, the `MacroCommand` 19 | * instantiates and calls `execute` on each of its `SubCommands` turn. 20 | * Each `SubCommand` will be passed a reference to the original 21 | * `Notification` that was passed to the `MacroCommand`'s 22 | * `execute` method. 23 | * 24 | * Unlike `SimpleCommand`, your subclass 25 | * should not override `execute`, but instead, should 26 | * override the `initializeMacroCommand` method, 27 | * calling `addSubCommand` once for each `SubCommand` 28 | * to be executed. 29 | * 30 | * @see {@link Controller} 31 | * @see {@link Notification} 32 | * @see {@link SimpleCommand} 33 | * 34 | * @class MacroCommand 35 | * @extends Notifier 36 | */ 37 | class MacroCommand extends SimpleCommand_1.SimpleCommand { 38 | /** 39 | * Constructor. 40 | * 41 | * You should not need to define a constructor, 42 | * instead, override the `initializeMacroCommand` 43 | * method. 44 | * 45 | * If your subclass does define a constructor, be 46 | * sure to call `super()`. 47 | * 48 | */ 49 | constructor() { 50 | super(); 51 | this.subCommands = []; 52 | this.initializeMacroCommand(); 53 | } 54 | /** 55 | * Initialize the `MacroCommand`. 56 | * 57 | * In your subclass, override this method to 58 | * initialize the `MacroCommand`'s `SubCommand` 59 | * list with `Command` class references like 60 | * this: 61 | * 62 | * ```ts 63 | * // Initialize MyMacroCommand 64 | * initializeMacroCommand() { 65 | * this.addSubCommand(() => new app.FirstCommand()); 66 | * this.addSubCommand(() => new app.SecondCommand()); 67 | * this.addSubCommand(() => new app.ThirdCommand()); 68 | * } 69 | * ``` 70 | * 71 | * Note that `SubCommand`s may be any `Command` implementor, 72 | * `MacroCommand`s or `SimpleCommands` are both acceptable. 73 | */ 74 | initializeMacroCommand() { 75 | } 76 | /** 77 | * Add a `SubCommand`. 78 | * 79 | * The `SubCommands` will be called in First In/First Out (FIFO) 80 | * order. 81 | * 82 | * @param {() => ICommand} factory - A factory function that creates an instance of ICommand. This function will be used to generate the sub-command. 83 | * @returns {void} 84 | */ 85 | addSubCommand(factory) { 86 | this.subCommands.push(factory); 87 | } 88 | /** 89 | * Execute this `MacroCommand`'s `SubCommands`. 90 | * 91 | * The `SubCommands` will be called in First In/First Out (FIFO) 92 | * order. 93 | * 94 | * @param {INotification} notification - The notification containing the data or command details to be processed. 95 | * @returns {void} 96 | */ 97 | execute(notification) { 98 | while (this.subCommands.length > 0) { 99 | const factory = this.subCommands.shift(); 100 | const command = factory === null || factory === void 0 ? void 0 : factory(); 101 | if (command) { 102 | command.initializeNotifier(this.multitonKey); 103 | command.execute(notification); 104 | } 105 | } 106 | } 107 | } 108 | exports.MacroCommand = MacroCommand; 109 | -------------------------------------------------------------------------------- /bin/cjs/patterns/command/SimpleCommand.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // SimpleCommand.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.SimpleCommand = void 0; 11 | const Notifier_1 = require("../observer/Notifier"); 12 | /** 13 | * A base `Command` implementation. 14 | * 15 | * Your subclass should override the `execute` 16 | * method where your business logic will handle the `Notification`. 17 | * 18 | * @see {@link Controller} 19 | * @see {@link Notification} 20 | * @see {@link MacroCommand} 21 | * 22 | * @class SimpleCommand 23 | * @extends Notifier 24 | */ 25 | class SimpleCommand extends Notifier_1.Notifier { 26 | /** 27 | * Fulfill the use-case initiated by the given `Notification`. 28 | * 29 | * In the Command Pattern, an application use-case typically 30 | * begins with some user action, which results in a `Notification` being broadcast, which 31 | * is handled by business logic in the `execute` method of an 32 | * `Command`. 33 | * 34 | * @param {INotification} notification - The notification containing the data or command details to be processed. 35 | * @returns {void} 36 | */ 37 | execute(notification) { 38 | } 39 | } 40 | exports.SimpleCommand = SimpleCommand; 41 | -------------------------------------------------------------------------------- /bin/cjs/patterns/mediator/Mediator.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // Mediator.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Mediator = void 0; 11 | const Notifier_1 = require("../observer/Notifier"); 12 | /** 13 | * A base `Mediator` implementation. 14 | * 15 | * @see {@link View} 16 | * 17 | * @class Mediator 18 | * @extends Notifier 19 | */ 20 | class Mediator extends Notifier_1.Notifier { 21 | /** 22 | * Constructor. 23 | * 24 | * @param {string} [name] - Optional name for the mediator. Defaults to `Mediator.NAME`. 25 | * @param {any} [viewComponent] - Optional view component associated with the mediator. 26 | */ 27 | constructor(name, viewComponent) { 28 | super(); 29 | this._name = name || Mediator.NAME; 30 | this._viewComponent = viewComponent; 31 | } 32 | /** 33 | * Called by the View when the Mediator is registered 34 | * 35 | * @returns {void} 36 | */ 37 | onRegister() { 38 | } 39 | /** 40 | * Called by the View when the Mediator is removed 41 | * 42 | * @returns {void} 43 | */ 44 | onRemove() { 45 | } 46 | /** 47 | * List the `Notification` names this 48 | * `Mediator` is interested in being notified of. 49 | * 50 | * @returns {string[]} An array of notification names. 51 | */ 52 | listNotificationInterests() { 53 | return []; 54 | } 55 | /** 56 | * Handle `Notification`s. 57 | * 58 | * Typically, this will be handled in a switch statement, 59 | * with one 'case' entry per `Notification` 60 | * the `Mediator` is interested in. 61 | * 62 | * @param {INotification} notification - The notification to handle. 63 | * @returns {void} 64 | */ 65 | handleNotification(notification) { 66 | } 67 | /** 68 | * the mediator name 69 | * 70 | * @returns {string} The name of the mediator. 71 | */ 72 | get name() { 73 | return this._name; 74 | } 75 | /** 76 | * Get the `Mediator`'s view component. 77 | * 78 | * Additionally, an implicit getter will usually 79 | * be defined in the subclass that casts the view 80 | * object to a type, like this: 81 | * 82 | * @returns {any} The view component. 83 | */ 84 | get viewComponent() { 85 | return this._viewComponent; 86 | } 87 | /** 88 | * Set the `Mediator`'s view component. 89 | * 90 | * @param {any} value - The new view component. 91 | */ 92 | set viewComponent(value) { 93 | this._viewComponent = value; 94 | } 95 | } 96 | exports.Mediator = Mediator; 97 | /** The default name for the mediator. 98 | * @type {string} */ 99 | Mediator.NAME = "Mediator"; 100 | -------------------------------------------------------------------------------- /bin/cjs/patterns/observer/Notification.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // Notification.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Notification = void 0; 11 | /** 12 | * A base `Notification` implementation. 13 | * 14 | * PureMVC does not rely upon underlying event models such 15 | * as the one provided with Flash, and ActionScript 3 does 16 | * not have an inherent event model. 17 | * 18 | * The Observer Pattern as implemented within PureMVC exists 19 | * to support event-driven communication between the 20 | * application and the actors of the MVC triad. 21 | * 22 | * Notifications are not meant to be a replacement for Events 23 | * in Flex/Flash/Apollo. Generally, `Mediator` implementors 24 | * place event listeners on their view components, which they 25 | * then handle in the usual way. This may lead to the broadcast of `Notification`s to 26 | * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command` 27 | * instances communicate with each other and `Mediator`s 28 | * by broadcasting `Notification`s. 29 | * 30 | * A key difference between Flash `Event`s and PureMVC 31 | * `Notification`s is that `Event`s follow the 32 | * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 33 | * until some parent component handles the `Event`, while 34 | * PureMVC `Notification`s follow a 'Publish/Subscribe' 35 | * pattern. PureMVC classes need not be related to each other in a 36 | * parent/child relationship in order to communicate with one another 37 | * using `Notification`s. 38 | * 39 | * @class Notification 40 | */ 41 | class Notification { 42 | /** 43 | * Constructor. 44 | * 45 | * @param {string} name - The name of the notification. 46 | * @param {any} [body] - Optional data to be included with the notification. 47 | * @param {string} [type] - Optional type of the notification. 48 | */ 49 | constructor(name, body, type) { 50 | this._name = name; 51 | this._body = body; 52 | this._type = type; 53 | } 54 | /** 55 | * Get the name of the `Notification` instance. 56 | * 57 | * @returns {string} The name of the notification. 58 | */ 59 | get name() { 60 | return this._name; 61 | } 62 | /** 63 | * Get the body of the `Notification` instance. 64 | * 65 | * @returns {any} The body of the notification. 66 | */ 67 | get body() { 68 | return this._body; 69 | } 70 | /** 71 | * Set the body of the `Notification` instance. 72 | * 73 | * @param {any} value - The new body to be set for the notification. 74 | */ 75 | set body(value) { 76 | this._body = value; 77 | } 78 | /** 79 | * Get the type of the `Notification` instance. 80 | * 81 | * @returns {string | undefined} The type of the notification, or `undefined` if not set. 82 | */ 83 | get type() { 84 | return this._type; 85 | } 86 | /** 87 | * Set the type of the `Notification` instance. 88 | * 89 | * @param {string | undefined} value - The new type to be set for the notification. 90 | */ 91 | set type(value) { 92 | this._type = value; 93 | } 94 | /** 95 | * Get the string representation of the `Notification` instance. 96 | * 97 | * @returns {string} A string representation of the notification. 98 | */ 99 | toString() { 100 | var _a; 101 | let msg = `Notification Name: ${this.name}`; 102 | msg += `\nBody: ${this.body ? this.body : "null"}`; 103 | msg += `\nType: ${(_a = this.type) !== null && _a !== void 0 ? _a : "null"}`; 104 | return msg; 105 | } 106 | } 107 | exports.Notification = Notification; 108 | -------------------------------------------------------------------------------- /bin/cjs/patterns/observer/Notifier.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // Notifier.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Notifier = void 0; 11 | const Facade_1 = require("../facade/Facade"); 12 | /** 13 | * A Base `Notifier` implementation. 14 | * 15 | * `MacroCommand, Command, Mediator` and `Proxy` 16 | * all have a need to send `Notifications`. 17 | * 18 | * The `Notifier` interface provides a common method called 19 | * `sendNotification` that relieves implementation code of 20 | * the necessity to actually construct `Notifications`. 21 | * 22 | * The `Notifier` class, which all the above-mentioned classes 23 | * extend, provides an initialized reference to the `Facade` 24 | * Multiton, which is required for the convenience method 25 | * for sending `Notifications`, but also eases implementation as these 26 | * classes have frequent `Facade` interactions and usually require 27 | * access to the facade anyway. 28 | * 29 | * NOTE: In the MultiCore version of the framework, there is one caveat to 30 | * notifiers, they cannot send notifications or reach the facade until they 31 | * have a valid multitonKey. 32 | * 33 | * The multitonKey is set: 34 | * - on a Command when it is executed by the Controller 35 | * - on a Mediator is registered with the View 36 | * - on a Proxy is registered with the Model. 37 | * 38 | * @see {@link Proxy} 39 | * @see {@link Facade} 40 | * @see {@link Mediator} 41 | * @see {@link MacroCommand} 42 | * @see {@link SimpleCommand} 43 | * 44 | * @class Notifier 45 | */ 46 | class Notifier { 47 | /** 48 | * Initialize this Notifier instance. 49 | * 50 | * This is how a Notifier gets its multitonKey. 51 | * Calls to sendNotification or to access the 52 | * facade will fail until after this method 53 | * has been called. 54 | * 55 | * Mediators, Commands or Proxies may override 56 | * this method in order to send notifications 57 | * or access the Multiton Facade instance as 58 | * soon as possible. They CANNOT access the facade 59 | * in their constructors, since this method will not 60 | * yet have been called. 61 | * 62 | * @param {string} key the multitonKey for this Notifier to use 63 | * @returns {void} 64 | */ 65 | initializeNotifier(key) { 66 | this.multitonKey = key; 67 | } 68 | /** 69 | * Create and send an `Notification`. 70 | * 71 | * Keeps us from having to construct new Notification 72 | * instances in our implementation code. 73 | * 74 | * @param {string} notificationName - The name of the notification to be sent. 75 | * @param {any} [body] - Optional data to be included with the notification. 76 | * @param {string} [type] - Optional type of the notification. 77 | * @returns {void} 78 | */ 79 | sendNotification(notificationName, body, type) { 80 | this.facade.sendNotification(notificationName, body, type); 81 | } 82 | /** 83 | * Return the Multiton Facade instance 84 | * 85 | * @returns {IFacade} The facade instance. 86 | * @throws {Error} If the multiton key is not initialized. 87 | */ 88 | get facade() { 89 | if (this.multitonKey == null) 90 | throw Error(Notifier.MULTITON_MSG); 91 | return Facade_1.Facade.getInstance(this.multitonKey, (key) => new Facade_1.Facade(key)); 92 | } 93 | } 94 | exports.Notifier = Notifier; 95 | /** Message Constants 96 | * @type {string} */ 97 | Notifier.MULTITON_MSG = "multitonKey for this Notifier not yet initialized!"; 98 | -------------------------------------------------------------------------------- /bin/cjs/patterns/observer/Observer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // Observer.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Observer = void 0; 11 | /** 12 | * A base `Observer` implementation. 13 | * 14 | * An `Observer` is an object that encapsulates information 15 | * about an interested object with a method that should 16 | * be called when a particular `Notification` is broadcast. 17 | * 18 | * In PureMVC, the `Observer` class assumes these responsibilities: 19 | * 20 | * - Encapsulate the notification (callback) method of the interested object. 21 | * - Encapsulate the notification context (this) of the interested object. 22 | * - Provide methods for setting the notification method and context. 23 | * - Provide a method for notifying the interested object. 24 | * 25 | * @class Observer 26 | */ 27 | class Observer { 28 | /** 29 | * Constructor. 30 | * 31 | * The notification method on the interested object should take 32 | * one parameter of type `Notification` 33 | * 34 | * @param {((notification: INotification) => void) | null} notify - The method to be called when a notification is received. Can be `null`. 35 | * @param {any | null} context - The context in which to call the `notifyMethod`. Can be `null`. 36 | */ 37 | constructor(notify, context) { 38 | this._notifyMethod = notify; 39 | this._notifyContext = context; 40 | } 41 | /** 42 | * Get the notification method. 43 | * 44 | * @returns {((notification: INotification) => void) | null} The current method or `null` if no method is set. 45 | */ 46 | get notifyMethod() { 47 | return this._notifyMethod; 48 | } 49 | /** 50 | * Set the notification method. 51 | * 52 | * The notification method should take one parameter of type `Notification`. 53 | * 54 | * @param {((notification: INotification) => void) | null} value - The method to set for handling notifications. Can be `null`. 55 | */ 56 | set notifyMethod(value) { 57 | this._notifyMethod = value; 58 | } 59 | /** 60 | * Get the notifyContext 61 | * 62 | * @returns {any | null} The current context or `null` if no context is set. 63 | */ 64 | get notifyContext() { 65 | return this._notifyContext; 66 | } 67 | /** 68 | * Set the notification context. 69 | * 70 | * @param {any | null} value - The context to set. Can be `null`. 71 | */ 72 | set notifyContext(value) { 73 | this._notifyContext = value; 74 | } 75 | /** 76 | * Notify the interested object. 77 | * 78 | * @param {INotification} notification - The notification to send to the observer. 79 | * @returns {void} 80 | */ 81 | notifyObserver(notification) { 82 | var _a; 83 | (_a = this.notifyMethod) === null || _a === void 0 ? void 0 : _a.call(this.notifyContext, notification); 84 | } 85 | /** 86 | * Compare an object to the notification context. 87 | * 88 | * @param {any} object - The object to compare with the observer's context. 89 | * @returns {boolean} `true` if the context is the same, otherwise `false`. 90 | */ 91 | compareNotifyContext(object) { 92 | return object == this.notifyContext; 93 | } 94 | } 95 | exports.Observer = Observer; 96 | -------------------------------------------------------------------------------- /bin/cjs/patterns/proxy/Proxy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // 3 | // Proxy.ts 4 | // PureMVC TypeScript Multicore 5 | // 6 | // Copyright(c) 2024 Saad Shams 7 | // Your reuse is governed by the BSD-3-Clause License 8 | // 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.Proxy = void 0; 11 | const Notifier_1 = require("../observer/Notifier"); 12 | /** 13 | * A base `Proxy` implementation. 14 | * 15 | * In PureMVC, `Proxy` classes are used to manage parts of the 16 | * application's data model. 17 | * 18 | * A `Proxy` might simply manage a reference to a local data object, 19 | * in which case interacting with it might involve setting and 20 | * getting of its data in synchronous fashion. 21 | * 22 | * `Proxy` classes are also used to encapsulate the application's 23 | * interaction with remote services to save or retrieve data, in which case, 24 | * we adopt an asynchronous idiom; setting data (or calling a method) on the 25 | * `Proxy` and listening for a `Notification` to be sent 26 | * when the `Proxy` has retrieved the data from the service. 27 | * 28 | * @see {@link Model} 29 | * 30 | * @class Proxy 31 | * @extends Notifier 32 | */ 33 | class Proxy extends Notifier_1.Notifier { 34 | /** 35 | * Constructor 36 | * 37 | * @param {string} [name] - The name of the proxy. Defaults to `Proxy.NAME` if not provided. 38 | * @param {any} [data] - The data associated with the proxy. Can be `null`. 39 | */ 40 | constructor(name, data) { 41 | super(); 42 | this._name = name || Proxy.NAME; 43 | this._data = data; 44 | } 45 | /** 46 | * Called by the Model when the Proxy is registered 47 | * 48 | * @returns {void} 49 | */ 50 | onRegister() { 51 | } 52 | /** 53 | * Called by the Model when the Proxy is removed 54 | * 55 | * @returns {void} 56 | */ 57 | onRemove() { 58 | } 59 | /** 60 | * Get the proxy name 61 | * 62 | * @returns {string} The name of the proxy. 63 | */ 64 | get name() { 65 | return this._name; 66 | } 67 | /** 68 | * Get the data object 69 | * 70 | * @returns {any} The current data or `undefined` if no data is set. 71 | */ 72 | get data() { 73 | return this._data; 74 | } 75 | /** 76 | * Set the data object 77 | * 78 | * @param {any} value - The data to set. Can be `null`. 79 | */ 80 | set data(value) { 81 | this._data = value; 82 | } 83 | } 84 | exports.Proxy = Proxy; 85 | /** 86 | * The default name for the Proxy. 87 | * 88 | * @type {string} 89 | */ 90 | Proxy.NAME = "Proxy"; 91 | -------------------------------------------------------------------------------- /bin/esm/core/Model.js: -------------------------------------------------------------------------------- 1 | // 2 | // Model.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | /** 9 | * A Multiton `Model` implementation. 10 | * 11 | * In PureMVC, the `Model` class provides 12 | * access to model objects (Proxies) by named lookup. 13 | * 14 | * The `Model` assumes these responsibilities: 15 | * 16 | * - Maintain a cache of `Proxy` instances. 17 | * - Provide methods for registering, retrieving, and removing 18 | * `Proxy` instances. 19 | * 20 | * Your application must register `Proxy` instances 21 | * with the `Model`. Typically, you use an 22 | * `Command` to create and register `Proxy` 23 | * instances once the `Facade` has initialized the Core 24 | * actors. 25 | * 26 | * @see {@link Proxy} 27 | * 28 | * @class Model 29 | */ 30 | export class Model { 31 | /** 32 | * Constructor. 33 | * 34 | * This `Model` implementation is a Multiton, 35 | * so you should not call the constructor 36 | * directly, but instead call the static Multiton 37 | * Factory method `Model.getInstance(multitonKey)` 38 | * 39 | * @param {string} key 40 | * 41 | * @throws {Error} Error if instance for this Multiton key instance has already been constructed 42 | */ 43 | constructor(key) { 44 | if (Model.instanceMap[key] != null) 45 | throw Error(Model.MULTITON_MSG); 46 | this.multitonKey = key; 47 | Model.instanceMap[key] = this; 48 | this.proxyMap = {}; 49 | this.initializeModel(); 50 | } 51 | /** 52 | * Initialize the `Model` instance. 53 | * 54 | * Called automatically by the constructor, this 55 | * is your opportunity to initialize the Multiton 56 | * instance in your subclass without overriding the 57 | * constructor. 58 | * 59 | * @returns {void} 60 | */ 61 | initializeModel() { 62 | } 63 | /** 64 | * `Model` Multiton Factory method. 65 | * 66 | * @param {string} key - The key used to identify the model instance. 67 | * @param {(key: string) => IModel} factory - A factory function that creates a new instance of the model if one does not already exist for the specified key. 68 | * @returns {IModel} The model instance associated with the given key. 69 | */ 70 | static getInstance(key, factory) { 71 | if (Model.instanceMap[key] == null) 72 | Model.instanceMap[key] = factory(key); 73 | return Model.instanceMap[key]; 74 | } 75 | /** 76 | * Register a `Proxy` with the `Model`. 77 | * 78 | * @param {IProxy} proxy - The proxy instance to be registered. 79 | * @returns {void} 80 | */ 81 | registerProxy(proxy) { 82 | proxy.initializeNotifier(this.multitonKey); 83 | this.proxyMap[proxy.name] = proxy; 84 | proxy.onRegister(); 85 | } 86 | /** 87 | * Retrieve a `Proxy` from the `Model`. 88 | * 89 | * @param {string} proxyName - The name of the proxy to retrieve. 90 | * @returns {IProxy | null} The proxy instance associated with the given name, or `null` if no such proxy exists. 91 | */ 92 | retrieveProxy(proxyName) { 93 | return this.proxyMap[proxyName] || null; 94 | } 95 | /** 96 | * Check if a Proxy is registered 97 | * 98 | * @param {string} proxyName - The name of the proxy to check. 99 | * @returns {boolean} `true` if a proxy with the specified name is registered; otherwise, `false`. 100 | */ 101 | hasProxy(proxyName) { 102 | return this.proxyMap[proxyName] != null; 103 | } 104 | /** 105 | * Remove a `Proxy` from the `Model`. 106 | * 107 | * @param {string} proxyName - The name of the proxy to be removed. 108 | * @returns {IProxy | null} The removed proxy instance, or `null` if no proxy with the given name was found. 109 | */ 110 | removeProxy(proxyName) { 111 | const proxy = this.proxyMap[proxyName]; 112 | if (!proxy) 113 | return null; 114 | delete this.proxyMap[proxyName]; 115 | proxy.onRemove(); 116 | return proxy; 117 | } 118 | /** 119 | * Remove a Model instance 120 | * 121 | * @param {string} key - The key used to identify the model instance to be removed. 122 | * @returns {void} 123 | */ 124 | static removeModel(key) { 125 | delete Model.instanceMap[key]; 126 | } 127 | } 128 | /** Message Constants 129 | * @type {string} */ 130 | Model.MULTITON_MSG = "Model instance for this Multiton key already constructed!"; 131 | /** Multiton Instances 132 | * @type {{ [key: string]: IModel }} */ 133 | Model.instanceMap = {}; 134 | -------------------------------------------------------------------------------- /bin/esm/index.js: -------------------------------------------------------------------------------- 1 | // 2 | // index.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | export { Controller } from "./core/Controller"; 9 | export { Model } from "./core/Model"; 10 | export { View } from "./core/View"; 11 | export { MacroCommand } from "./patterns/command/MacroCommand"; 12 | export { SimpleCommand } from "./patterns/command/SimpleCommand"; 13 | export { Facade } from "./patterns/facade/Facade"; 14 | export { Mediator } from "./patterns/mediator/Mediator"; 15 | export { Notification } from "./patterns/observer/Notification"; 16 | export { Notifier } from "./patterns/observer/Notifier"; 17 | export { Observer } from "./patterns/observer/Observer"; 18 | export { Proxy } from "./patterns/proxy/Proxy"; 19 | -------------------------------------------------------------------------------- /bin/esm/package.json: -------------------------------------------------------------------------------- 1 | {"type": "module"} 2 | -------------------------------------------------------------------------------- /bin/esm/patterns/command/MacroCommand.js: -------------------------------------------------------------------------------- 1 | // 2 | // MacroCommand.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | import { SimpleCommand } from "./SimpleCommand"; 9 | /** 10 | * A base `Command` implementation that executes other `Command`s. 11 | * 12 | * A `MacroCommand` maintains a list of 13 | * `Command` Class references called `SubCommands`. 14 | * 15 | * When `execute` is called, the `MacroCommand` 16 | * instantiates and calls `execute` on each of its `SubCommands` turn. 17 | * Each `SubCommand` will be passed a reference to the original 18 | * `Notification` that was passed to the `MacroCommand`'s 19 | * `execute` method. 20 | * 21 | * Unlike `SimpleCommand`, your subclass 22 | * should not override `execute`, but instead, should 23 | * override the `initializeMacroCommand` method, 24 | * calling `addSubCommand` once for each `SubCommand` 25 | * to be executed. 26 | * 27 | * @see {@link Controller} 28 | * @see {@link Notification} 29 | * @see {@link SimpleCommand} 30 | * 31 | * @class MacroCommand 32 | * @extends Notifier 33 | */ 34 | export class MacroCommand extends SimpleCommand { 35 | /** 36 | * Constructor. 37 | * 38 | * You should not need to define a constructor, 39 | * instead, override the `initializeMacroCommand` 40 | * method. 41 | * 42 | * If your subclass does define a constructor, be 43 | * sure to call `super()`. 44 | * 45 | */ 46 | constructor() { 47 | super(); 48 | this.subCommands = []; 49 | this.initializeMacroCommand(); 50 | } 51 | /** 52 | * Initialize the `MacroCommand`. 53 | * 54 | * In your subclass, override this method to 55 | * initialize the `MacroCommand`'s `SubCommand` 56 | * list with `Command` class references like 57 | * this: 58 | * 59 | * ```ts 60 | * // Initialize MyMacroCommand 61 | * initializeMacroCommand() { 62 | * this.addSubCommand(() => new app.FirstCommand()); 63 | * this.addSubCommand(() => new app.SecondCommand()); 64 | * this.addSubCommand(() => new app.ThirdCommand()); 65 | * } 66 | * ``` 67 | * 68 | * Note that `SubCommand`s may be any `Command` implementor, 69 | * `MacroCommand`s or `SimpleCommands` are both acceptable. 70 | */ 71 | initializeMacroCommand() { 72 | } 73 | /** 74 | * Add a `SubCommand`. 75 | * 76 | * The `SubCommands` will be called in First In/First Out (FIFO) 77 | * order. 78 | * 79 | * @param {() => ICommand} factory - A factory function that creates an instance of ICommand. This function will be used to generate the sub-command. 80 | * @returns {void} 81 | */ 82 | addSubCommand(factory) { 83 | this.subCommands.push(factory); 84 | } 85 | /** 86 | * Execute this `MacroCommand`'s `SubCommands`. 87 | * 88 | * The `SubCommands` will be called in First In/First Out (FIFO) 89 | * order. 90 | * 91 | * @param {INotification} notification - The notification containing the data or command details to be processed. 92 | * @returns {void} 93 | */ 94 | execute(notification) { 95 | while (this.subCommands.length > 0) { 96 | const factory = this.subCommands.shift(); 97 | const command = factory === null || factory === void 0 ? void 0 : factory(); 98 | if (command) { 99 | command.initializeNotifier(this.multitonKey); 100 | command.execute(notification); 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /bin/esm/patterns/command/SimpleCommand.js: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCommand.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | import { Notifier } from "../observer/Notifier"; 9 | /** 10 | * A base `Command` implementation. 11 | * 12 | * Your subclass should override the `execute` 13 | * method where your business logic will handle the `Notification`. 14 | * 15 | * @see {@link Controller} 16 | * @see {@link Notification} 17 | * @see {@link MacroCommand} 18 | * 19 | * @class SimpleCommand 20 | * @extends Notifier 21 | */ 22 | export class SimpleCommand extends Notifier { 23 | /** 24 | * Fulfill the use-case initiated by the given `Notification`. 25 | * 26 | * In the Command Pattern, an application use-case typically 27 | * begins with some user action, which results in a `Notification` being broadcast, which 28 | * is handled by business logic in the `execute` method of an 29 | * `Command`. 30 | * 31 | * @param {INotification} notification - The notification containing the data or command details to be processed. 32 | * @returns {void} 33 | */ 34 | execute(notification) { 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bin/esm/patterns/mediator/Mediator.js: -------------------------------------------------------------------------------- 1 | // 2 | // Mediator.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | import { Notifier } from "../observer/Notifier"; 9 | /** 10 | * A base `Mediator` implementation. 11 | * 12 | * @see {@link View} 13 | * 14 | * @class Mediator 15 | * @extends Notifier 16 | */ 17 | export class Mediator extends Notifier { 18 | /** 19 | * Constructor. 20 | * 21 | * @param {string} [name] - Optional name for the mediator. Defaults to `Mediator.NAME`. 22 | * @param {any} [viewComponent] - Optional view component associated with the mediator. 23 | */ 24 | constructor(name, viewComponent) { 25 | super(); 26 | this._name = name || Mediator.NAME; 27 | this._viewComponent = viewComponent; 28 | } 29 | /** 30 | * Called by the View when the Mediator is registered 31 | * 32 | * @returns {void} 33 | */ 34 | onRegister() { 35 | } 36 | /** 37 | * Called by the View when the Mediator is removed 38 | * 39 | * @returns {void} 40 | */ 41 | onRemove() { 42 | } 43 | /** 44 | * List the `Notification` names this 45 | * `Mediator` is interested in being notified of. 46 | * 47 | * @returns {string[]} An array of notification names. 48 | */ 49 | listNotificationInterests() { 50 | return []; 51 | } 52 | /** 53 | * Handle `Notification`s. 54 | * 55 | * Typically, this will be handled in a switch statement, 56 | * with one 'case' entry per `Notification` 57 | * the `Mediator` is interested in. 58 | * 59 | * @param {INotification} notification - The notification to handle. 60 | * @returns {void} 61 | */ 62 | handleNotification(notification) { 63 | } 64 | /** 65 | * the mediator name 66 | * 67 | * @returns {string} The name of the mediator. 68 | */ 69 | get name() { 70 | return this._name; 71 | } 72 | /** 73 | * Get the `Mediator`'s view component. 74 | * 75 | * Additionally, an implicit getter will usually 76 | * be defined in the subclass that casts the view 77 | * object to a type, like this: 78 | * 79 | * @returns {any} The view component. 80 | */ 81 | get viewComponent() { 82 | return this._viewComponent; 83 | } 84 | /** 85 | * Set the `Mediator`'s view component. 86 | * 87 | * @param {any} value - The new view component. 88 | */ 89 | set viewComponent(value) { 90 | this._viewComponent = value; 91 | } 92 | } 93 | /** The default name for the mediator. 94 | * @type {string} */ 95 | Mediator.NAME = "Mediator"; 96 | -------------------------------------------------------------------------------- /bin/esm/patterns/observer/Notification.js: -------------------------------------------------------------------------------- 1 | // 2 | // Notification.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | /** 9 | * A base `Notification` implementation. 10 | * 11 | * PureMVC does not rely upon underlying event models such 12 | * as the one provided with Flash, and ActionScript 3 does 13 | * not have an inherent event model. 14 | * 15 | * The Observer Pattern as implemented within PureMVC exists 16 | * to support event-driven communication between the 17 | * application and the actors of the MVC triad. 18 | * 19 | * Notifications are not meant to be a replacement for Events 20 | * in Flex/Flash/Apollo. Generally, `Mediator` implementors 21 | * place event listeners on their view components, which they 22 | * then handle in the usual way. This may lead to the broadcast of `Notification`s to 23 | * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command` 24 | * instances communicate with each other and `Mediator`s 25 | * by broadcasting `Notification`s. 26 | * 27 | * A key difference between Flash `Event`s and PureMVC 28 | * `Notification`s is that `Event`s follow the 29 | * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 30 | * until some parent component handles the `Event`, while 31 | * PureMVC `Notification`s follow a 'Publish/Subscribe' 32 | * pattern. PureMVC classes need not be related to each other in a 33 | * parent/child relationship in order to communicate with one another 34 | * using `Notification`s. 35 | * 36 | * @class Notification 37 | */ 38 | export class Notification { 39 | /** 40 | * Constructor. 41 | * 42 | * @param {string} name - The name of the notification. 43 | * @param {any} [body] - Optional data to be included with the notification. 44 | * @param {string} [type] - Optional type of the notification. 45 | */ 46 | constructor(name, body, type) { 47 | this._name = name; 48 | this._body = body; 49 | this._type = type; 50 | } 51 | /** 52 | * Get the name of the `Notification` instance. 53 | * 54 | * @returns {string} The name of the notification. 55 | */ 56 | get name() { 57 | return this._name; 58 | } 59 | /** 60 | * Get the body of the `Notification` instance. 61 | * 62 | * @returns {any} The body of the notification. 63 | */ 64 | get body() { 65 | return this._body; 66 | } 67 | /** 68 | * Set the body of the `Notification` instance. 69 | * 70 | * @param {any} value - The new body to be set for the notification. 71 | */ 72 | set body(value) { 73 | this._body = value; 74 | } 75 | /** 76 | * Get the type of the `Notification` instance. 77 | * 78 | * @returns {string | undefined} The type of the notification, or `undefined` if not set. 79 | */ 80 | get type() { 81 | return this._type; 82 | } 83 | /** 84 | * Set the type of the `Notification` instance. 85 | * 86 | * @param {string | undefined} value - The new type to be set for the notification. 87 | */ 88 | set type(value) { 89 | this._type = value; 90 | } 91 | /** 92 | * Get the string representation of the `Notification` instance. 93 | * 94 | * @returns {string} A string representation of the notification. 95 | */ 96 | toString() { 97 | var _a; 98 | let msg = `Notification Name: ${this.name}`; 99 | msg += `\nBody: ${this.body ? this.body : "null"}`; 100 | msg += `\nType: ${(_a = this.type) !== null && _a !== void 0 ? _a : "null"}`; 101 | return msg; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /bin/esm/patterns/observer/Notifier.js: -------------------------------------------------------------------------------- 1 | // 2 | // Notifier.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | import { Facade } from "../facade/Facade"; 9 | /** 10 | * A Base `Notifier` implementation. 11 | * 12 | * `MacroCommand, Command, Mediator` and `Proxy` 13 | * all have a need to send `Notifications`. 14 | * 15 | * The `Notifier` interface provides a common method called 16 | * `sendNotification` that relieves implementation code of 17 | * the necessity to actually construct `Notifications`. 18 | * 19 | * The `Notifier` class, which all the above-mentioned classes 20 | * extend, provides an initialized reference to the `Facade` 21 | * Multiton, which is required for the convenience method 22 | * for sending `Notifications`, but also eases implementation as these 23 | * classes have frequent `Facade` interactions and usually require 24 | * access to the facade anyway. 25 | * 26 | * NOTE: In the MultiCore version of the framework, there is one caveat to 27 | * notifiers, they cannot send notifications or reach the facade until they 28 | * have a valid multitonKey. 29 | * 30 | * The multitonKey is set: 31 | * - on a Command when it is executed by the Controller 32 | * - on a Mediator is registered with the View 33 | * - on a Proxy is registered with the Model. 34 | * 35 | * @see {@link Proxy} 36 | * @see {@link Facade} 37 | * @see {@link Mediator} 38 | * @see {@link MacroCommand} 39 | * @see {@link SimpleCommand} 40 | * 41 | * @class Notifier 42 | */ 43 | export class Notifier { 44 | /** 45 | * Initialize this Notifier instance. 46 | * 47 | * This is how a Notifier gets its multitonKey. 48 | * Calls to sendNotification or to access the 49 | * facade will fail until after this method 50 | * has been called. 51 | * 52 | * Mediators, Commands or Proxies may override 53 | * this method in order to send notifications 54 | * or access the Multiton Facade instance as 55 | * soon as possible. They CANNOT access the facade 56 | * in their constructors, since this method will not 57 | * yet have been called. 58 | * 59 | * @param {string} key the multitonKey for this Notifier to use 60 | * @returns {void} 61 | */ 62 | initializeNotifier(key) { 63 | this.multitonKey = key; 64 | } 65 | /** 66 | * Create and send an `Notification`. 67 | * 68 | * Keeps us from having to construct new Notification 69 | * instances in our implementation code. 70 | * 71 | * @param {string} notificationName - The name of the notification to be sent. 72 | * @param {any} [body] - Optional data to be included with the notification. 73 | * @param {string} [type] - Optional type of the notification. 74 | * @returns {void} 75 | */ 76 | sendNotification(notificationName, body, type) { 77 | this.facade.sendNotification(notificationName, body, type); 78 | } 79 | /** 80 | * Return the Multiton Facade instance 81 | * 82 | * @returns {IFacade} The facade instance. 83 | * @throws {Error} If the multiton key is not initialized. 84 | */ 85 | get facade() { 86 | if (this.multitonKey == null) 87 | throw Error(Notifier.MULTITON_MSG); 88 | return Facade.getInstance(this.multitonKey, (key) => new Facade(key)); 89 | } 90 | } 91 | /** Message Constants 92 | * @type {string} */ 93 | Notifier.MULTITON_MSG = "multitonKey for this Notifier not yet initialized!"; 94 | -------------------------------------------------------------------------------- /bin/esm/patterns/observer/Observer.js: -------------------------------------------------------------------------------- 1 | // 2 | // Observer.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | /** 9 | * A base `Observer` implementation. 10 | * 11 | * An `Observer` is an object that encapsulates information 12 | * about an interested object with a method that should 13 | * be called when a particular `Notification` is broadcast. 14 | * 15 | * In PureMVC, the `Observer` class assumes these responsibilities: 16 | * 17 | * - Encapsulate the notification (callback) method of the interested object. 18 | * - Encapsulate the notification context (this) of the interested object. 19 | * - Provide methods for setting the notification method and context. 20 | * - Provide a method for notifying the interested object. 21 | * 22 | * @class Observer 23 | */ 24 | export class Observer { 25 | /** 26 | * Constructor. 27 | * 28 | * The notification method on the interested object should take 29 | * one parameter of type `Notification` 30 | * 31 | * @param {((notification: INotification) => void) | null} notify - The method to be called when a notification is received. Can be `null`. 32 | * @param {any | null} context - The context in which to call the `notifyMethod`. Can be `null`. 33 | */ 34 | constructor(notify, context) { 35 | this._notifyMethod = notify; 36 | this._notifyContext = context; 37 | } 38 | /** 39 | * Get the notification method. 40 | * 41 | * @returns {((notification: INotification) => void) | null} The current method or `null` if no method is set. 42 | */ 43 | get notifyMethod() { 44 | return this._notifyMethod; 45 | } 46 | /** 47 | * Set the notification method. 48 | * 49 | * The notification method should take one parameter of type `Notification`. 50 | * 51 | * @param {((notification: INotification) => void) | null} value - The method to set for handling notifications. Can be `null`. 52 | */ 53 | set notifyMethod(value) { 54 | this._notifyMethod = value; 55 | } 56 | /** 57 | * Get the notifyContext 58 | * 59 | * @returns {any | null} The current context or `null` if no context is set. 60 | */ 61 | get notifyContext() { 62 | return this._notifyContext; 63 | } 64 | /** 65 | * Set the notification context. 66 | * 67 | * @param {any | null} value - The context to set. Can be `null`. 68 | */ 69 | set notifyContext(value) { 70 | this._notifyContext = value; 71 | } 72 | /** 73 | * Notify the interested object. 74 | * 75 | * @param {INotification} notification - The notification to send to the observer. 76 | * @returns {void} 77 | */ 78 | notifyObserver(notification) { 79 | var _a; 80 | (_a = this.notifyMethod) === null || _a === void 0 ? void 0 : _a.call(this.notifyContext, notification); 81 | } 82 | /** 83 | * Compare an object to the notification context. 84 | * 85 | * @param {any} object - The object to compare with the observer's context. 86 | * @returns {boolean} `true` if the context is the same, otherwise `false`. 87 | */ 88 | compareNotifyContext(object) { 89 | return object == this.notifyContext; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /bin/esm/patterns/proxy/Proxy.js: -------------------------------------------------------------------------------- 1 | // 2 | // Proxy.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | import { Notifier } from "../observer/Notifier"; 9 | /** 10 | * A base `Proxy` implementation. 11 | * 12 | * In PureMVC, `Proxy` classes are used to manage parts of the 13 | * application's data model. 14 | * 15 | * A `Proxy` might simply manage a reference to a local data object, 16 | * in which case interacting with it might involve setting and 17 | * getting of its data in synchronous fashion. 18 | * 19 | * `Proxy` classes are also used to encapsulate the application's 20 | * interaction with remote services to save or retrieve data, in which case, 21 | * we adopt an asynchronous idiom; setting data (or calling a method) on the 22 | * `Proxy` and listening for a `Notification` to be sent 23 | * when the `Proxy` has retrieved the data from the service. 24 | * 25 | * @see {@link Model} 26 | * 27 | * @class Proxy 28 | * @extends Notifier 29 | */ 30 | export class Proxy extends Notifier { 31 | /** 32 | * Constructor 33 | * 34 | * @param {string} [name] - The name of the proxy. Defaults to `Proxy.NAME` if not provided. 35 | * @param {any} [data] - The data associated with the proxy. Can be `null`. 36 | */ 37 | constructor(name, data) { 38 | super(); 39 | this._name = name || Proxy.NAME; 40 | this._data = data; 41 | } 42 | /** 43 | * Called by the Model when the Proxy is registered 44 | * 45 | * @returns {void} 46 | */ 47 | onRegister() { 48 | } 49 | /** 50 | * Called by the Model when the Proxy is removed 51 | * 52 | * @returns {void} 53 | */ 54 | onRemove() { 55 | } 56 | /** 57 | * Get the proxy name 58 | * 59 | * @returns {string} The name of the proxy. 60 | */ 61 | get name() { 62 | return this._name; 63 | } 64 | /** 65 | * Get the data object 66 | * 67 | * @returns {any} The current data or `undefined` if no data is set. 68 | */ 69 | get data() { 70 | return this._data; 71 | } 72 | /** 73 | * Set the data object 74 | * 75 | * @param {any} value - The data to set. Can be `null`. 76 | */ 77 | set data(value) { 78 | this._data = value; 79 | } 80 | } 81 | /** 82 | * The default name for the Proxy. 83 | * 84 | * @type {string} 85 | */ 86 | Proxy.NAME = "Proxy"; 87 | -------------------------------------------------------------------------------- /bin/types/core/Controller.d.ts: -------------------------------------------------------------------------------- 1 | import { IController } from "../interfaces/IController"; 2 | import { IView } from "../interfaces/IView"; 3 | import { ICommand } from "../interfaces/ICommand"; 4 | import { INotification } from "../interfaces/INotification"; 5 | /** 6 | * A Multiton `Controller` implementation. 7 | * 8 | * In PureMVC, the `Controller` class follows the 9 | * 'Command and Controller' strategy, and assumes these 10 | * responsibilities: 11 | * 12 | * 13 | * - Remembering which `Command`s 14 | * are intended to handle which `Notifications`. 15 | * - Registering itself as an `Observer` with 16 | * the `View` for each `Notification` 17 | * that it has a `Command` mapping for. 18 | * - Creating a new instance of the proper `Command` 19 | * to handle a given `Notification` when notified by the `View`. 20 | * - Calling the `Command`'s `execute` 21 | * method, passing in the `Notification`. 22 | * 23 | * 24 | * Your application must register `Commands` with the 25 | * Controller. 26 | * 27 | * The simplest way is to subclass `Facade`, 28 | * and use its `initializeController` method to add your 29 | * registrations. 30 | * 31 | * @see {@link View} 32 | * @see {@link Observer} 33 | * @see {@link Notification} 34 | * @see {@link SimpleCommand} 35 | * @see {@link MacroCommand} 36 | * 37 | * @class Controller 38 | */ 39 | export declare class Controller implements IController { 40 | /** Message Constants 41 | * @type {string} */ 42 | protected static MULTITON_MSG: string; 43 | /** Multiton Instances 44 | * @type {{ [key: string]: IController }} */ 45 | protected static instanceMap: { 46 | [key: string]: IController; 47 | }; 48 | /** The Multiton Key for this Core 49 | * @type {string} */ 50 | protected multitonKey: string; 51 | /** Local reference to View 52 | * @type {IView | undefined} */ 53 | protected view?: IView; 54 | /** Mapping of Notification names to Command factories 55 | * @type {{ [key: string]: () => ICommand }} */ 56 | protected commandMap: { 57 | [key: string]: () => ICommand; 58 | }; 59 | /** 60 | * Constructor. 61 | * 62 | * This `Controller` implementation is a Multiton, 63 | * so you should not call the constructor 64 | * directly, but instead call the static Factory method, 65 | * passing the unique key for this instance 66 | * `Controller.getInstance(multitonKey)` 67 | * 68 | * @param {string} key 69 | * 70 | * @throws {Error} Error if instance for this Multiton key has already been constructed 71 | */ 72 | constructor(key: string); 73 | /** 74 | * Initialize the Multiton `Controller` instance. 75 | * 76 | * Called automatically by the constructor. 77 | * 78 | * Note that if you are using a subclass of `View` 79 | * in your application, you should also subclass `Controller` 80 | * and override the `initializeController` method in the 81 | * following way: 82 | * 83 | * ```ts 84 | * // ensure that the Controller is talking to my View implementation 85 | * initializeController() { 86 | * this.view = MyView.getInstance("ViewTestKey1", (key: string) => new View(key)); 87 | * } 88 | * ``` 89 | * @returns {void} 90 | */ 91 | protected initializeController(): void; 92 | /** 93 | * `Controller` Multiton Factory method. 94 | * 95 | * @param {string} key - The key used to identify the controller instance. 96 | * @param {(key: string) => IController} factory - A factory function that creates a new instance of the controller if one does not already exist for the specified key. 97 | * @returns {IController} The controller instance associated with the given key. 98 | */ 99 | static getInstance(key: string, factory: (key: string) => IController): IController; 100 | /** 101 | * Register a particular `Command` class as the handler 102 | * for a particular `Notification`. 103 | * 104 | * If an `Command` has already been registered to 105 | * handle `Notification`s with this name, it is no longer 106 | * used, the new `Command` is used instead. 107 | * 108 | * The Observer for the new Command is only created if this the 109 | * first time a Command has been registered for this Notification name. 110 | * 111 | * @param {string} notificationName - The name of the notification to associate with the command. 112 | * @param {() => ICommand} factory - A factory function that returns an instance of the command. 113 | * @returns {void} 114 | */ 115 | registerCommand(notificationName: string, factory: () => ICommand): void; 116 | /** 117 | * If a `Command` has previously been registered 118 | * to handle the given `Notification`, then it is executed. 119 | * 120 | * @param {INotification} notification - The notification containing the data or command details needed for execution. 121 | * @returns {void} 122 | */ 123 | executeCommand(notification: INotification): void; 124 | /** 125 | * Check if a Command is registered for a given Notification 126 | * 127 | * @param {string} notificationName - The name of the notification to check for a registered command. 128 | * @returns {boolean} `true` if a command is registered for the specified notification name; otherwise, `false`. 129 | */ 130 | hasCommand(notificationName: string): boolean; 131 | /** 132 | * Remove a previously registered `Command` to `Notification` mapping. 133 | * 134 | * @param {string} notificationName - The name of the notification for which the associated command should be removed. 135 | * @returns {void} 136 | */ 137 | removeCommand(notificationName: string): void; 138 | /** 139 | * Remove a Controller instance 140 | * 141 | * @param {string} key - The key used to identify the controller instance to be removed. 142 | * @returns {void} 143 | */ 144 | static removeController(key: string): void; 145 | } 146 | -------------------------------------------------------------------------------- /bin/types/core/Model.d.ts: -------------------------------------------------------------------------------- 1 | import { IModel } from "../interfaces/IModel"; 2 | import { IProxy } from "../interfaces/IProxy"; 3 | /** 4 | * A Multiton `Model` implementation. 5 | * 6 | * In PureMVC, the `Model` class provides 7 | * access to model objects (Proxies) by named lookup. 8 | * 9 | * The `Model` assumes these responsibilities: 10 | * 11 | * - Maintain a cache of `Proxy` instances. 12 | * - Provide methods for registering, retrieving, and removing 13 | * `Proxy` instances. 14 | * 15 | * Your application must register `Proxy` instances 16 | * with the `Model`. Typically, you use an 17 | * `Command` to create and register `Proxy` 18 | * instances once the `Facade` has initialized the Core 19 | * actors. 20 | * 21 | * @see {@link Proxy} 22 | * 23 | * @class Model 24 | */ 25 | export declare class Model implements IModel { 26 | /** Message Constants 27 | * @type {string} */ 28 | protected static MULTITON_MSG: string; 29 | /** Multiton Instances 30 | * @type {{ [key: string]: IModel }} */ 31 | protected static instanceMap: { 32 | [key: string]: IModel; 33 | }; 34 | /** The Multiton Key for this Core 35 | * @type {string} */ 36 | protected multitonKey: string; 37 | /** Mapping of proxyNames to IProxy instances 38 | * @type {{ [key: string]: IProxy }} */ 39 | protected proxyMap: { 40 | [key: string]: IProxy; 41 | }; 42 | /** 43 | * Constructor. 44 | * 45 | * This `Model` implementation is a Multiton, 46 | * so you should not call the constructor 47 | * directly, but instead call the static Multiton 48 | * Factory method `Model.getInstance(multitonKey)` 49 | * 50 | * @param {string} key 51 | * 52 | * @throws {Error} Error if instance for this Multiton key instance has already been constructed 53 | */ 54 | constructor(key: string); 55 | /** 56 | * Initialize the `Model` instance. 57 | * 58 | * Called automatically by the constructor, this 59 | * is your opportunity to initialize the Multiton 60 | * instance in your subclass without overriding the 61 | * constructor. 62 | * 63 | * @returns {void} 64 | */ 65 | protected initializeModel(): void; 66 | /** 67 | * `Model` Multiton Factory method. 68 | * 69 | * @param {string} key - The key used to identify the model instance. 70 | * @param {(key: string) => IModel} factory - A factory function that creates a new instance of the model if one does not already exist for the specified key. 71 | * @returns {IModel} The model instance associated with the given key. 72 | */ 73 | static getInstance(key: string, factory: (key: string) => IModel): IModel; 74 | /** 75 | * Register a `Proxy` with the `Model`. 76 | * 77 | * @param {IProxy} proxy - The proxy instance to be registered. 78 | * @returns {void} 79 | */ 80 | registerProxy(proxy: IProxy): void; 81 | /** 82 | * Retrieve a `Proxy` from the `Model`. 83 | * 84 | * @param {string} proxyName - The name of the proxy to retrieve. 85 | * @returns {IProxy | null} The proxy instance associated with the given name, or `null` if no such proxy exists. 86 | */ 87 | retrieveProxy(proxyName: string): IProxy | null; 88 | /** 89 | * Check if a Proxy is registered 90 | * 91 | * @param {string} proxyName - The name of the proxy to check. 92 | * @returns {boolean} `true` if a proxy with the specified name is registered; otherwise, `false`. 93 | */ 94 | hasProxy(proxyName: string): boolean; 95 | /** 96 | * Remove a `Proxy` from the `Model`. 97 | * 98 | * @param {string} proxyName - The name of the proxy to be removed. 99 | * @returns {IProxy | null} The removed proxy instance, or `null` if no proxy with the given name was found. 100 | */ 101 | removeProxy(proxyName: string): IProxy | null; 102 | /** 103 | * Remove a Model instance 104 | * 105 | * @param {string} key - The key used to identify the model instance to be removed. 106 | * @returns {void} 107 | */ 108 | static removeModel(key: string): void; 109 | } 110 | -------------------------------------------------------------------------------- /bin/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export type { IController } from "./interfaces/IController"; 2 | export type { IModel } from "./interfaces/IModel"; 3 | export type { IView } from "./interfaces/IView"; 4 | export type { ICommand } from "./interfaces/ICommand"; 5 | export type { IFacade } from "./interfaces/IFacade"; 6 | export type { IMediator } from "./interfaces/IMediator"; 7 | export type { INotification } from "./interfaces/INotification"; 8 | export type { INotifier } from "./interfaces/INotifier"; 9 | export type { IObserver } from "./interfaces/IObserver"; 10 | export type { IProxy } from "./interfaces/IProxy"; 11 | export { Controller } from "./core/Controller"; 12 | export { Model } from "./core/Model"; 13 | export { View } from "./core/View"; 14 | export { MacroCommand } from "./patterns/command/MacroCommand"; 15 | export { SimpleCommand } from "./patterns/command/SimpleCommand"; 16 | export { Facade } from "./patterns/facade/Facade"; 17 | export { Mediator } from "./patterns/mediator/Mediator"; 18 | export { Notification } from "./patterns/observer/Notification"; 19 | export { Notifier } from "./patterns/observer/Notifier"; 20 | export { Observer } from "./patterns/observer/Observer"; 21 | export { Proxy } from "./patterns/proxy/Proxy"; 22 | -------------------------------------------------------------------------------- /bin/types/interfaces/ICommand.d.ts: -------------------------------------------------------------------------------- 1 | import { INotifier } from "./INotifier"; 2 | import { INotification } from "./INotification"; 3 | /** 4 | * The interface definition for a PureMVC Command. 5 | * 6 | * @see {@link INotification} 7 | * 8 | * @interface ICommand 9 | * @extends {INotifier} 10 | */ 11 | export interface ICommand extends INotifier { 12 | /** 13 | * Execute the `ICommand`'s logic to handle a given `INotification`. 14 | * 15 | * @param {INotification} notification - The notification carrying the data and type necessary for executing the command. 16 | * @returns {void} 17 | */ 18 | execute(notification: INotification): void; 19 | } 20 | -------------------------------------------------------------------------------- /bin/types/interfaces/IController.d.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "./ICommand"; 2 | import { INotification } from "./INotification"; 3 | /** 4 | * `IController` The interface definition for a PureMVC `Controller`. 5 | * 6 | * In PureMVC, an `IController` implementor 7 | * follows the 'Command and Controller' strategy, and 8 | * assumes these responsibilities: 9 | * 10 | * - Remembering which `ICommands` are intended to handle which `INotifications`. 11 | * 12 | * - Registering itself as an `IObserver` with the View for each `INotification` that it has an `ICommand` mapping for. 13 | * 14 | * - Creating a new instance of the proper `ICommand` to handle a given `INotification` when notified by the `View`. 15 | * 16 | * - Calling the `ICommand`'s execute method, passing in the `INotification`. 17 | * 18 | * @interface IController 19 | */ 20 | export interface IController { 21 | /** 22 | * Register a particular `ICommand` class as the handler 23 | * for a particular INotification. 24 | * 25 | * @param {string} notificationName - the name of the `INotification` 26 | * @param {() => ICommand} factory - A factory that returns `ICommand` 27 | * @returns {void} 28 | */ 29 | registerCommand(notificationName: string, factory: () => ICommand): void; 30 | /** 31 | * Execute the `ICommand` previously registered as the 32 | * handler for `INotifications` with the given notification name. 33 | * 34 | * @param {INotification} notification - the `INotification` to execute the associated `ICommand` for 35 | * @returns {void} 36 | */ 37 | executeCommand(notification: INotification): void; 38 | /** 39 | * Check if a `Command` is registered for a given `Notification` 40 | * 41 | * @param {string} notificationName - The name of the notification to check. 42 | * @returns {boolean} `true` if a command is registered for the notification name, `false` otherwise. 43 | */ 44 | hasCommand(notificationName: string): boolean; 45 | /** 46 | * Remove a previously registered `ICommand` to `INotification` mapping. 47 | * 48 | * @param {string} notificationName - the name of the INotification to remove the ICommand mapping for 49 | * @returns {void} 50 | */ 51 | removeCommand(notificationName: string): void; 52 | } 53 | -------------------------------------------------------------------------------- /bin/types/interfaces/IFacade.d.ts: -------------------------------------------------------------------------------- 1 | import { INotifier } from "./INotifier"; 2 | import { ICommand } from "./ICommand"; 3 | import { IMediator } from "./IMediator"; 4 | import { INotification } from "./INotification"; 5 | import { IProxy } from "./IProxy"; 6 | /** 7 | * `IFacade` The interface definition for a PureMVC `Facade`. 8 | * 9 | * The `Facade` Pattern suggests providing a single 10 | * class to act as a central point of communication 11 | * for a subsystem. 12 | * 13 | * In PureMVC, the `Facade` acts as an interface between 14 | * the core MVC actors (`Model`, `View`, `Controller`) and 15 | * the rest of your application. 16 | * 17 | * @interface IFacade 18 | * @extends {INotifier} 19 | */ 20 | export interface IFacade extends INotifier { 21 | /** 22 | * Register an `ICommand` with the `Controller` 23 | * 24 | * @param {string} notificationName - the name of the `INotification` to associate the `ICommand` with. 25 | * @param {() => ICommand} factory - A factory that creates an instance of the `ICommand` to be registered. 26 | * @returns {void} 27 | */ 28 | registerCommand(notificationName: string, factory: () => ICommand): void; 29 | /** 30 | * Check if a `ICommand` is registered for a given `Notification` 31 | * 32 | * @param {string} notificationName - The name of the notification to check. 33 | * @returns {boolean} `true` if a command is registered for the notification name, `false` otherwise. 34 | */ 35 | hasCommand(notificationName: string): boolean; 36 | /** 37 | * Remove a previously registered `ICommand` to `INotification` mapping from the `Controller`. 38 | * 39 | * @param {string} notificationName - the name of the `INotification` to remove the `ICommand` mapping for 40 | * @returns {void} 41 | */ 42 | removeCommand(notificationName: string): void; 43 | /** 44 | * Register an `IProxy` with the `Model` by name. 45 | * 46 | * @param {IProxy} proxy - the IProxy to be registered with the Model. 47 | * @returns {void} 48 | */ 49 | registerProxy(proxy: IProxy): void; 50 | /** 51 | * Retrieve a `IProxy` from the `Model` by name. 52 | * 53 | * @param {string} proxyName - the name of the `IProxy` instance to be retrieved. 54 | * @returns {IProxy | null} the `IProxy` previously registered by `proxyName` with the `Model`. 55 | */ 56 | retrieveProxy(proxyName: string): IProxy | null; 57 | /** 58 | * Check if a `Proxy` is registered 59 | * 60 | * @param {string} proxyName - The name of the proxy to check. 61 | * @returns {boolean} `true` if a proxy is registered with the name, `false` otherwise. 62 | */ 63 | hasProxy(proxyName: string): boolean; 64 | /** 65 | * Remove an `IProxy` instance from the `Model` by name. 66 | * 67 | * @param {string} proxyName - the `IProxy` to remove from the `Model`. 68 | * @returns {IProxy | null} The removed proxy instance if found, or `null` if no proxy was registered with the given name. 69 | */ 70 | removeProxy(proxyName: string): IProxy | null; 71 | /** 72 | * Register an `IMediator` instance with the `View`. 73 | * 74 | * @param {IMediator} mediator - a reference to the `IMediator` instance 75 | * @returns {void} 76 | */ 77 | registerMediator(mediator: IMediator): void; 78 | /** 79 | * Retrieve an `IMediator` instance from the `View`. 80 | * 81 | * @param {string} mediatorName - the name of the `IMediator` instance to retrieve 82 | * @returns {IMediator | null} The mediator instance if found, or `null` if no mediator is registered with the given name. 83 | */ 84 | retrieveMediator(mediatorName: string): IMediator | null; 85 | /** 86 | * Check if a `Mediator` is registered or not 87 | * 88 | * @param {string} mediatorName - The name of the mediator to check. 89 | * @returns {boolean} `true` if a mediator is registered with the name, `false` otherwise. 90 | */ 91 | hasMediator(mediatorName: string): boolean; 92 | /** 93 | * Remove a `IMediator` instance from the `View`. 94 | * 95 | * @param {string} mediatorName - The name of the mediator to remove. 96 | * @returns {IMediator | null} The removed mediator instance if found, or `null` if no mediator was registered with the given name. 97 | */ 98 | removeMediator(mediatorName: string): IMediator | null; 99 | /** 100 | * Notify Observers. 101 | * 102 | * This method is left public mostly for backward 103 | * compatibility, and to allow you to send custom 104 | * notification classes using the facade. 105 | * 106 | * Usually you should just call `sendNotification` 107 | * and pass the parameters, never having to 108 | * construct the notification yourself. 109 | * 110 | * @param {INotification} notification - the `INotification` to have the `View` notify `Observers` of. 111 | * @returns {void} 112 | */ 113 | notifyObservers(notification: INotification): void; 114 | } 115 | -------------------------------------------------------------------------------- /bin/types/interfaces/IMediator.d.ts: -------------------------------------------------------------------------------- 1 | import { INotifier } from "./INotifier"; 2 | import { INotification } from "./INotification"; 3 | /** 4 | * `IMediator` The interface definition for a PureMVC `Mediator`. 5 | * 6 | * In PureMVC, `IMediator` implementors assume these responsibilities: 7 | * 8 | * - Implement a common method which returns a list of all `INotifications` the `IMediator` has interest in. 9 | * 10 | * - Implement a notification callback method. 11 | * 12 | * - Implement methods that are called when the `IMediator` is registered or removed from the View. 13 | * 14 | * Additionally, `IMediators` typically: 15 | * 16 | * - Act as an intermediary between one or more view components such as text boxes or list controls, maintaining references and coordinating their behavior. 17 | * 18 | * - In Flash-based apps, this is often the place where event listeners are added to view components, and their handlers implemented. 19 | * 20 | * - Respond to and generate `INotifications`, interacting with of the rest of the PureMVC app. 21 | * 22 | * When an `IMediator` is registered with the `IView`, 23 | * the `IView` will call the `IMediator`'s 24 | * `listNotificationInterests` method. The `IMediator` will 25 | * return an Array of `INotification` names which 26 | * it wishes to be notified about. 27 | * 28 | * The `IView` will then create an `Observer` object 29 | * encapsulating that `IMediator`'s (`handleNotification`) method 30 | * and register it as an `Observer` for each `INotification` name returned by 31 | * `listNotificationInterests`. 32 | * 33 | * @interface IMediator 34 | * @extends {INotifier} 35 | */ 36 | export interface IMediator extends INotifier { 37 | /** 38 | * The name of the mediator. 39 | * 40 | * @type {string} 41 | */ 42 | readonly name: string; 43 | /** 44 | * The view component associated with the mediator. 45 | * 46 | * @type {any} 47 | */ 48 | viewComponent: any; 49 | /** 50 | * Called by the View when the `Mediator` is registered 51 | * 52 | * @returns {void} 53 | */ 54 | onRegister(): void; 55 | /** 56 | * Called by the View when the `Mediator` is removed 57 | * 58 | * @returns {void} 59 | */ 60 | onRemove(): void; 61 | /** 62 | * List `INotification` interests. 63 | * 64 | * @returns {string[]} an Array of the `INotification` names this `IMediator` has an interest in. 65 | */ 66 | listNotificationInterests(): string[]; 67 | /** 68 | * Handle an `INotification`. 69 | * 70 | * @param {INotification} notification - the `INotification` to be handled 71 | * @returns {void} 72 | */ 73 | handleNotification(notification: INotification): void; 74 | } 75 | -------------------------------------------------------------------------------- /bin/types/interfaces/IModel.d.ts: -------------------------------------------------------------------------------- 1 | import { IProxy } from "./IProxy"; 2 | /** 3 | * `IModel` The interface definition for a PureMVC `Model`. 4 | * 5 | * In PureMVC, `IModel` implementors provide 6 | * access to `IProxy` objects by named lookup. 7 | * 8 | * An `IModel` assumes these responsibilities: 9 | * 10 | * - Maintain a cache of `IProxy` instances 11 | * 12 | * - Provide methods for registering, retrieving, and removing `IProxy` instances 13 | * 14 | * @interface IModel 15 | */ 16 | export interface IModel { 17 | /** 18 | * Register an `IProxy` instance with the `Model`. 19 | * 20 | * @param {IProxy} proxy - an object reference to be held by the `Model`. 21 | * @returns {void} 22 | */ 23 | registerProxy(proxy: IProxy): void; 24 | /** 25 | * Retrieve an `IProxy` instance from the `Model`. 26 | * 27 | * @param {string} proxyName - The name of the proxy to retrieve. 28 | * @returns {IProxy | null} The `IProxy` if registered, otherwise null. 29 | */ 30 | retrieveProxy(proxyName: string): IProxy | null; 31 | /** 32 | * Check if a `Proxy` is registered 33 | * 34 | * @param {string} proxyName - The name of the proxy to check. 35 | * @returns {boolean} True if the `IProxy` is registered, otherwise false. 36 | */ 37 | hasProxy(proxyName: string): boolean; 38 | /** 39 | * Remove an `IProxy` instance from the `Model`. 40 | * 41 | * @param {string} proxyName - The name of the proxy to remove. 42 | * @returns {IProxy | null} The removed `IProxy` if found, otherwise null. 43 | */ 44 | removeProxy(proxyName: string): IProxy | null; 45 | } 46 | -------------------------------------------------------------------------------- /bin/types/interfaces/INotification.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * `INotification` The interface definition for a PureMVC `Notification`. 3 | * 4 | * PureMVC does not rely upon underlying event models such 5 | * as the one provided with Flash, and ActionScript 3 does 6 | * not have an inherent event model. 7 | * 8 | * The `Observer` Pattern as implemented within PureMVC exists 9 | * to support event-driven communication between the 10 | * application and the actors of the MVC triad. 11 | * 12 | * `Notifications` are not meant to be a replacement for Events 13 | * in Flex/Flash/AIR. Generally, `IMediator` implementors 14 | * place event listeners on their view components, which they 15 | * then handle in the usual way. This may lead to the broadcast of `Notifications` to 16 | * trigger `ICommands` or to communicate with other `IMediators`. `IProxy` and `ICommand` 17 | * instances communicate with each other and `IMediators` 18 | * by broadcasting `INotifications`. 19 | * 20 | * A key difference between Flash Events and PureMVC 21 | * `Notifications` is that Events follow the 22 | * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 23 | * until some parent component handles the Event, while 24 | * PureMVC `Notifications` follow a 'Publish/Subscribe' 25 | * pattern. PureMVC classes need not be related to each other in a 26 | * parent/child relationship in order to communicate with one another 27 | * using `Notifications`. 28 | * 29 | * @interface INotification 30 | */ 31 | export interface INotification { 32 | /** 33 | * The name of the notification. 34 | * 35 | * @type {string} 36 | */ 37 | readonly name: string; 38 | /** 39 | * The body of the notification. 40 | * 41 | * @type {any} 42 | */ 43 | body?: any; 44 | /** 45 | * The type of the notification. 46 | * 47 | * @type {string} 48 | */ 49 | type?: string; 50 | /** 51 | * Get the string representation of the `INotification` instance 52 | * 53 | * @returns {string} A string representation of the notification. 54 | */ 55 | toString(): string; 56 | } 57 | -------------------------------------------------------------------------------- /bin/types/interfaces/INotifier.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * `INotifier` The interface definition for a PureMVC `Notifier`. 3 | * 4 | * `MacroCommand`, `Command`, `Mediator` and `Proxy` 5 | * all have a need to send `Notifications`. 6 | * 7 | * The `INotifier` interface provides a common method called 8 | * `sendNotification` that relieves implementation code of 9 | * the necessity to actually construct `Notifications`. 10 | * 11 | * The `Notifier` class, which all the above-mentioned classes 12 | * extend, also provides an initialized reference to the `Facade` 13 | * Multiton, which is required for the convenience method 14 | * for sending `Notifications`, but also eases implementation as these 15 | * classes have frequent `Facade` interactions and usually require 16 | * access to the facade anyway. 17 | * 18 | * @interface INotifier 19 | */ 20 | export interface INotifier { 21 | /** 22 | * Initialize this `INotifier` instance. 23 | * 24 | * This is how a `Notifier` get to Calls to 25 | * `sendNotification` or to access the 26 | * facade will fail until after this method 27 | * has been called. 28 | * 29 | * @param {string} key - The key used to initialize the notifier. 30 | * @returns {void} 31 | */ 32 | initializeNotifier(key: string): void; 33 | /** 34 | * Send a `INotification`. 35 | * 36 | * Convenience method to prevent having to construct new 37 | * notification instances in our implementation code. 38 | * 39 | * @param {string} notificationName - The name of the notification to send. 40 | * @param {any} [body] - Optional data associated with the notification. 41 | * @param {string} [type] - Optional type of the notification. 42 | * @returns {void} 43 | */ 44 | sendNotification(notificationName: string, body?: any, type?: string): void; 45 | } 46 | -------------------------------------------------------------------------------- /bin/types/interfaces/IObserver.d.ts: -------------------------------------------------------------------------------- 1 | import { INotification } from "./INotification"; 2 | /** 3 | * `IObserver` The interface definition for a PureMVC `Observer`. 4 | * 5 | * In PureMVC, `IObserver` implementors assume these responsibilities: 6 | * 7 | * - Encapsulate the notification (callback) method of the interested object. 8 | * 9 | * - Encapsulate the notification context (self) of the interested object. 10 | * 11 | * - Provide methods for setting the interested object notification method and context. 12 | * 13 | * - Provide a method for notifying the interested object. 14 | * 15 | * PureMVC does not rely upon underlying event 16 | * models such as the one provided with Flash, 17 | * and ActionScript 3 does not have an inherent 18 | * event model. 19 | * 20 | * The `Observer` Pattern as implemented within 21 | * PureMVC exists to support event driven communication 22 | * between the application and the actors of the 23 | * MVC triad. 24 | * 25 | * An `Observer` is an object that encapsulates information 26 | * about an interested object with a notification method that 27 | * should be called when an `INotification` is broadcast. 28 | * The Observer then acts as a proxy for notifying the interested object. 29 | * 30 | * Observers can receive Notifications by having their 31 | * `notifyObserver` method invoked, passing 32 | * in an object implementing the `INotification` interface, such 33 | * as a subclass of `Notification`. 34 | * 35 | * @interface IObserver 36 | */ 37 | export interface IObserver { 38 | /** 39 | * The method to be called when a notification is received. 40 | * 41 | * @type {((notification: INotification) => void) | null} 42 | */ 43 | notifyMethod?: ((notification: INotification) => void) | null; 44 | /** 45 | * The context in which the notification method should be called. 46 | * 47 | * @type {any | null} 48 | */ 49 | notifyContext?: any | null; 50 | /** 51 | * Notify the interested object. 52 | * 53 | * @param {INotification} notification - the `INotification` to pass to the interested object's notification method 54 | * @returns {void} 55 | */ 56 | notifyObserver(notification: INotification): void; 57 | /** 58 | * Compare the given object to the notification context object. 59 | * 60 | * @param {any} object - The object to compare with the `notifyContext`. 61 | * @returns {boolean} `true` if the object is the same as the `notifyContext`, otherwise `false`. 62 | */ 63 | compareNotifyContext(object: any): boolean; 64 | } 65 | -------------------------------------------------------------------------------- /bin/types/interfaces/IProxy.d.ts: -------------------------------------------------------------------------------- 1 | import { INotifier } from "./INotifier"; 2 | /** 3 | * `IProxy` The interface definition for a PureMVC `Proxy`. 4 | * 5 | * In PureMVC, `IProxy` implementors assume these responsibilities: 6 | * 7 | * - Implement a common method which returns the name of the Proxy. 8 | * 9 | * - Provide methods for setting and getting the data object. 10 | * 11 | * Additionally, `IProxy`ies typically: 12 | * 13 | * - Maintain references to one or more pieces of model data. 14 | * 15 | * - Provide methods for manipulating that data. 16 | * 17 | * - Generate `INotifications` when their model data changes. 18 | * 19 | * - Expose their name as a public static const called `NAME`, if they are not instantiated multiple times. 20 | * 21 | * - Encapsulate interaction with local or remote services used to fetch and persist model data. 22 | * 23 | * @interface IProxy 24 | * @extends INotifier 25 | */ 26 | export interface IProxy extends INotifier { 27 | /** 28 | * The name of the proxy. 29 | * 30 | * @type {string} 31 | */ 32 | readonly name: string; 33 | /** 34 | * The data associated with the proxy. 35 | * 36 | * @type {any} 37 | */ 38 | data?: any; 39 | /** 40 | * Called by the Model when the Proxy is registered 41 | * 42 | * @returns {void} 43 | */ 44 | onRegister(): void; 45 | /** 46 | * Called by the Model when the Proxy is removed 47 | * 48 | * @returns {void} 49 | */ 50 | onRemove(): void; 51 | } 52 | -------------------------------------------------------------------------------- /bin/types/interfaces/IView.d.ts: -------------------------------------------------------------------------------- 1 | import { IMediator } from "./IMediator"; 2 | import { INotification } from "./INotification"; 3 | import { IObserver } from "./IObserver"; 4 | /** 5 | * `IView` The interface definition for a PureMVC `View`. 6 | * 7 | * In PureMVC, the View class assumes these responsibilities: 8 | * 9 | * - Maintain a cache of `IMediator` instances. 10 | * 11 | * - Provide methods for registering, retrieving, and removing `IMediators`. 12 | * 13 | * - Managing the observer lists for each `INotification` in the application. 14 | * 15 | * - Providing a method for attaching `IObservers` to an `INotification`'s observer list. 16 | * 17 | * - Providing a method for broadcasting an `INotification`. 18 | * 19 | * - Notifying the `IObservers` of a given `INotification` when it is broadcast. 20 | * 21 | * @interface IView 22 | */ 23 | export interface IView { 24 | /** 25 | * Register an `IObserver` to be notified 26 | * of `INotifications` with a given name. 27 | * 28 | * @param {string} notificationName - The name of the notification to register the observer for. 29 | * @param {IObserver} observer - The observer to be registered. 30 | * @returns {void} 31 | */ 32 | registerObserver(notificationName: string, observer: IObserver): void; 33 | /** 34 | * Notify the `IObservers` for a particular `INotification`. 35 | * 36 | * All previously attached `IObservers` for this `INotification`'s 37 | * list are notified and are passed a reference to the `INotification` in 38 | * the order in which they were registered. 39 | * 40 | * @param {INotification} notification - the `INotification` to notify `IObservers` of. 41 | * @returns {void} 42 | */ 43 | notifyObservers(notification: INotification): void; 44 | /** 45 | * Remove a group of observers from the observer list for a given Notification name. 46 | * 47 | * @param {string} notificationName - which observer list to remove from 48 | * @param {any} notifyContext - removed the observers with this object as their `notifyContext` 49 | * @returns {void} 50 | */ 51 | removeObserver(notificationName: string, notifyContext: any): void; 52 | /** 53 | * Register an `IMediator` instance with the View. 54 | * 55 | * Registers the `IMediator` so that it can be retrieved by name, 56 | * and further interrogates the `IMediator` for its 57 | * `INotification` interests. 58 | * 59 | * If the `IMediator` returns any `INotification` 60 | * names to be notified about, an `Observer` is created encapsulating 61 | * the `IMediator` instance's `handleNotification` method 62 | * and registering it as an `Observer` for all `INotifications` the 63 | * `IMediator` is interested in. 64 | * 65 | * @param {IMediator} mediator - The `IMediator` to be registered. 66 | * @returns {void} 67 | */ 68 | registerMediator(mediator: IMediator): void; 69 | /** 70 | * Retrieve an `IMediator` from the View. 71 | * 72 | * @param {string} mediatorName - the name of the `IMediator` instance to retrieve. 73 | * @returns {IMediator | null} The `IMediator` associated with the given name, or `null` if not found. 74 | */ 75 | retrieveMediator(mediatorName: string): IMediator | null; 76 | /** 77 | * Check if a `IMediator` is registered or not 78 | * 79 | * @param {string} mediatorName - The name of the `IMediator` to check. 80 | * @returns {boolean} `true` if the `IMediator` is registered, otherwise `false`. 81 | */ 82 | hasMediator(mediatorName: string): boolean; 83 | /** 84 | * Remove an `IMediator` from the View. 85 | * 86 | * @param {string} mediatorName - name of the `IMediator` instance to be removed. 87 | * @returns {IMediator | null} The removed `IMediator`, or `null` if not found. 88 | */ 89 | removeMediator(mediatorName: string): IMediator | null; 90 | } 91 | -------------------------------------------------------------------------------- /bin/types/patterns/command/MacroCommand.d.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "../../interfaces/ICommand"; 2 | import { INotification } from "../../interfaces/INotification"; 3 | import { SimpleCommand } from "./SimpleCommand"; 4 | /** 5 | * A base `Command` implementation that executes other `Command`s. 6 | * 7 | * A `MacroCommand` maintains a list of 8 | * `Command` Class references called `SubCommands`. 9 | * 10 | * When `execute` is called, the `MacroCommand` 11 | * instantiates and calls `execute` on each of its `SubCommands` turn. 12 | * Each `SubCommand` will be passed a reference to the original 13 | * `Notification` that was passed to the `MacroCommand`'s 14 | * `execute` method. 15 | * 16 | * Unlike `SimpleCommand`, your subclass 17 | * should not override `execute`, but instead, should 18 | * override the `initializeMacroCommand` method, 19 | * calling `addSubCommand` once for each `SubCommand` 20 | * to be executed. 21 | * 22 | * @see {@link Controller} 23 | * @see {@link Notification} 24 | * @see {@link SimpleCommand} 25 | * 26 | * @class MacroCommand 27 | * @extends Notifier 28 | */ 29 | export declare class MacroCommand extends SimpleCommand { 30 | /** An array of functions, each of which returns an instance of ICommand. 31 | * @type {(() => ICommand)[]} */ 32 | private subCommands; 33 | /** 34 | * Constructor. 35 | * 36 | * You should not need to define a constructor, 37 | * instead, override the `initializeMacroCommand` 38 | * method. 39 | * 40 | * If your subclass does define a constructor, be 41 | * sure to call `super()`. 42 | * 43 | */ 44 | constructor(); 45 | /** 46 | * Initialize the `MacroCommand`. 47 | * 48 | * In your subclass, override this method to 49 | * initialize the `MacroCommand`'s `SubCommand` 50 | * list with `Command` class references like 51 | * this: 52 | * 53 | * ```ts 54 | * // Initialize MyMacroCommand 55 | * initializeMacroCommand() { 56 | * this.addSubCommand(() => new app.FirstCommand()); 57 | * this.addSubCommand(() => new app.SecondCommand()); 58 | * this.addSubCommand(() => new app.ThirdCommand()); 59 | * } 60 | * ``` 61 | * 62 | * Note that `SubCommand`s may be any `Command` implementor, 63 | * `MacroCommand`s or `SimpleCommands` are both acceptable. 64 | */ 65 | initializeMacroCommand(): void; 66 | /** 67 | * Add a `SubCommand`. 68 | * 69 | * The `SubCommands` will be called in First In/First Out (FIFO) 70 | * order. 71 | * 72 | * @param {() => ICommand} factory - A factory function that creates an instance of ICommand. This function will be used to generate the sub-command. 73 | * @returns {void} 74 | */ 75 | protected addSubCommand(factory: () => ICommand): void; 76 | /** 77 | * Execute this `MacroCommand`'s `SubCommands`. 78 | * 79 | * The `SubCommands` will be called in First In/First Out (FIFO) 80 | * order. 81 | * 82 | * @param {INotification} notification - The notification containing the data or command details to be processed. 83 | * @returns {void} 84 | */ 85 | execute(notification: INotification): void; 86 | } 87 | -------------------------------------------------------------------------------- /bin/types/patterns/command/SimpleCommand.d.ts: -------------------------------------------------------------------------------- 1 | import { ICommand } from "../../interfaces/ICommand"; 2 | import { INotification } from "../../interfaces/INotification"; 3 | import { Notifier } from "../observer/Notifier"; 4 | /** 5 | * A base `Command` implementation. 6 | * 7 | * Your subclass should override the `execute` 8 | * method where your business logic will handle the `Notification`. 9 | * 10 | * @see {@link Controller} 11 | * @see {@link Notification} 12 | * @see {@link MacroCommand} 13 | * 14 | * @class SimpleCommand 15 | * @extends Notifier 16 | */ 17 | export declare class SimpleCommand extends Notifier implements ICommand { 18 | /** 19 | * Fulfill the use-case initiated by the given `Notification`. 20 | * 21 | * In the Command Pattern, an application use-case typically 22 | * begins with some user action, which results in a `Notification` being broadcast, which 23 | * is handled by business logic in the `execute` method of an 24 | * `Command`. 25 | * 26 | * @param {INotification} notification - The notification containing the data or command details to be processed. 27 | * @returns {void} 28 | */ 29 | execute(notification: INotification): void; 30 | } 31 | -------------------------------------------------------------------------------- /bin/types/patterns/mediator/Mediator.d.ts: -------------------------------------------------------------------------------- 1 | import { IMediator } from "../../interfaces/IMediator"; 2 | import { INotification } from "../../interfaces/INotification"; 3 | import { Notifier } from "../observer/Notifier"; 4 | /** 5 | * A base `Mediator` implementation. 6 | * 7 | * @see {@link View} 8 | * 9 | * @class Mediator 10 | * @extends Notifier 11 | */ 12 | export declare class Mediator extends Notifier implements IMediator { 13 | /** The default name for the mediator. 14 | * @type {string} */ 15 | static NAME: string; 16 | /** the mediator name 17 | @type {string} */ 18 | protected readonly _name: string; 19 | /** The view component 20 | * @type {any} */ 21 | protected _viewComponent?: any; 22 | /** 23 | * Constructor. 24 | * 25 | * @param {string} [name] - Optional name for the mediator. Defaults to `Mediator.NAME`. 26 | * @param {any} [viewComponent] - Optional view component associated with the mediator. 27 | */ 28 | constructor(name?: string, viewComponent?: any); 29 | /** 30 | * Called by the View when the Mediator is registered 31 | * 32 | * @returns {void} 33 | */ 34 | onRegister(): void; 35 | /** 36 | * Called by the View when the Mediator is removed 37 | * 38 | * @returns {void} 39 | */ 40 | onRemove(): void; 41 | /** 42 | * List the `Notification` names this 43 | * `Mediator` is interested in being notified of. 44 | * 45 | * @returns {string[]} An array of notification names. 46 | */ 47 | listNotificationInterests(): string[]; 48 | /** 49 | * Handle `Notification`s. 50 | * 51 | * Typically, this will be handled in a switch statement, 52 | * with one 'case' entry per `Notification` 53 | * the `Mediator` is interested in. 54 | * 55 | * @param {INotification} notification - The notification to handle. 56 | * @returns {void} 57 | */ 58 | handleNotification(notification: INotification): void; 59 | /** 60 | * the mediator name 61 | * 62 | * @returns {string} The name of the mediator. 63 | */ 64 | get name(): string; 65 | /** 66 | * Get the `Mediator`'s view component. 67 | * 68 | * Additionally, an implicit getter will usually 69 | * be defined in the subclass that casts the view 70 | * object to a type, like this: 71 | * 72 | * @returns {any} The view component. 73 | */ 74 | get viewComponent(): any; 75 | /** 76 | * Set the `Mediator`'s view component. 77 | * 78 | * @param {any} value - The new view component. 79 | */ 80 | set viewComponent(value: any); 81 | } 82 | -------------------------------------------------------------------------------- /bin/types/patterns/observer/Notification.d.ts: -------------------------------------------------------------------------------- 1 | import { INotification } from "../../interfaces/INotification"; 2 | /** 3 | * A base `Notification` implementation. 4 | * 5 | * PureMVC does not rely upon underlying event models such 6 | * as the one provided with Flash, and ActionScript 3 does 7 | * not have an inherent event model. 8 | * 9 | * The Observer Pattern as implemented within PureMVC exists 10 | * to support event-driven communication between the 11 | * application and the actors of the MVC triad. 12 | * 13 | * Notifications are not meant to be a replacement for Events 14 | * in Flex/Flash/Apollo. Generally, `Mediator` implementors 15 | * place event listeners on their view components, which they 16 | * then handle in the usual way. This may lead to the broadcast of `Notification`s to 17 | * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command` 18 | * instances communicate with each other and `Mediator`s 19 | * by broadcasting `Notification`s. 20 | * 21 | * A key difference between Flash `Event`s and PureMVC 22 | * `Notification`s is that `Event`s follow the 23 | * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 24 | * until some parent component handles the `Event`, while 25 | * PureMVC `Notification`s follow a 'Publish/Subscribe' 26 | * pattern. PureMVC classes need not be related to each other in a 27 | * parent/child relationship in order to communicate with one another 28 | * using `Notification`s. 29 | * 30 | * @class Notification 31 | */ 32 | export declare class Notification implements INotification { 33 | /** the name of the notification instance 34 | * @type {string} */ 35 | private readonly _name; 36 | /** the body of the notification instance 37 | * @type {any} */ 38 | private _body?; 39 | /** 40 | * @type {string | undefined } */ 41 | private _type?; 42 | /** 43 | * Constructor. 44 | * 45 | * @param {string} name - The name of the notification. 46 | * @param {any} [body] - Optional data to be included with the notification. 47 | * @param {string} [type] - Optional type of the notification. 48 | */ 49 | constructor(name: string, body?: any, type?: string); 50 | /** 51 | * Get the name of the `Notification` instance. 52 | * 53 | * @returns {string} The name of the notification. 54 | */ 55 | get name(): string; 56 | /** 57 | * Get the body of the `Notification` instance. 58 | * 59 | * @returns {any} The body of the notification. 60 | */ 61 | get body(): any; 62 | /** 63 | * Set the body of the `Notification` instance. 64 | * 65 | * @param {any} value - The new body to be set for the notification. 66 | */ 67 | set body(value: any); 68 | /** 69 | * Get the type of the `Notification` instance. 70 | * 71 | * @returns {string | undefined} The type of the notification, or `undefined` if not set. 72 | */ 73 | get type(): string | undefined; 74 | /** 75 | * Set the type of the `Notification` instance. 76 | * 77 | * @param {string | undefined} value - The new type to be set for the notification. 78 | */ 79 | set type(value: string | undefined); 80 | /** 81 | * Get the string representation of the `Notification` instance. 82 | * 83 | * @returns {string} A string representation of the notification. 84 | */ 85 | toString(): string; 86 | } 87 | -------------------------------------------------------------------------------- /bin/types/patterns/observer/Notifier.d.ts: -------------------------------------------------------------------------------- 1 | import { INotifier } from "../../interfaces/INotifier"; 2 | import { IFacade } from "../../interfaces/IFacade"; 3 | /** 4 | * A Base `Notifier` implementation. 5 | * 6 | * `MacroCommand, Command, Mediator` and `Proxy` 7 | * all have a need to send `Notifications`. 8 | * 9 | * The `Notifier` interface provides a common method called 10 | * `sendNotification` that relieves implementation code of 11 | * the necessity to actually construct `Notifications`. 12 | * 13 | * The `Notifier` class, which all the above-mentioned classes 14 | * extend, provides an initialized reference to the `Facade` 15 | * Multiton, which is required for the convenience method 16 | * for sending `Notifications`, but also eases implementation as these 17 | * classes have frequent `Facade` interactions and usually require 18 | * access to the facade anyway. 19 | * 20 | * NOTE: In the MultiCore version of the framework, there is one caveat to 21 | * notifiers, they cannot send notifications or reach the facade until they 22 | * have a valid multitonKey. 23 | * 24 | * The multitonKey is set: 25 | * - on a Command when it is executed by the Controller 26 | * - on a Mediator is registered with the View 27 | * - on a Proxy is registered with the Model. 28 | * 29 | * @see {@link Proxy} 30 | * @see {@link Facade} 31 | * @see {@link Mediator} 32 | * @see {@link MacroCommand} 33 | * @see {@link SimpleCommand} 34 | * 35 | * @class Notifier 36 | */ 37 | export declare class Notifier implements INotifier { 38 | /** Message Constants 39 | * @type {string} */ 40 | protected static MULTITON_MSG: string; 41 | /** The Multiton Key for this app 42 | * @type {string} */ 43 | protected multitonKey: string; 44 | /** 45 | * Initialize this Notifier instance. 46 | * 47 | * This is how a Notifier gets its multitonKey. 48 | * Calls to sendNotification or to access the 49 | * facade will fail until after this method 50 | * has been called. 51 | * 52 | * Mediators, Commands or Proxies may override 53 | * this method in order to send notifications 54 | * or access the Multiton Facade instance as 55 | * soon as possible. They CANNOT access the facade 56 | * in their constructors, since this method will not 57 | * yet have been called. 58 | * 59 | * @param {string} key the multitonKey for this Notifier to use 60 | * @returns {void} 61 | */ 62 | initializeNotifier(key: string): void; 63 | /** 64 | * Create and send an `Notification`. 65 | * 66 | * Keeps us from having to construct new Notification 67 | * instances in our implementation code. 68 | * 69 | * @param {string} notificationName - The name of the notification to be sent. 70 | * @param {any} [body] - Optional data to be included with the notification. 71 | * @param {string} [type] - Optional type of the notification. 72 | * @returns {void} 73 | */ 74 | sendNotification(notificationName: string, body?: any, type?: string): void; 75 | /** 76 | * Return the Multiton Facade instance 77 | * 78 | * @returns {IFacade} The facade instance. 79 | * @throws {Error} If the multiton key is not initialized. 80 | */ 81 | get facade(): IFacade; 82 | } 83 | -------------------------------------------------------------------------------- /bin/types/patterns/observer/Observer.d.ts: -------------------------------------------------------------------------------- 1 | import { IObserver } from "../../interfaces/IObserver"; 2 | import { INotification } from "../../interfaces/INotification"; 3 | /** 4 | * A base `Observer` implementation. 5 | * 6 | * An `Observer` is an object that encapsulates information 7 | * about an interested object with a method that should 8 | * be called when a particular `Notification` is broadcast. 9 | * 10 | * In PureMVC, the `Observer` class assumes these responsibilities: 11 | * 12 | * - Encapsulate the notification (callback) method of the interested object. 13 | * - Encapsulate the notification context (this) of the interested object. 14 | * - Provide methods for setting the notification method and context. 15 | * - Provide a method for notifying the interested object. 16 | * 17 | * @class Observer 18 | */ 19 | export declare class Observer implements IObserver { 20 | private _notifyMethod?; 21 | private _notifyContext?; 22 | /** 23 | * Constructor. 24 | * 25 | * The notification method on the interested object should take 26 | * one parameter of type `Notification` 27 | * 28 | * @param {((notification: INotification) => void) | null} notify - The method to be called when a notification is received. Can be `null`. 29 | * @param {any | null} context - The context in which to call the `notifyMethod`. Can be `null`. 30 | */ 31 | constructor(notify?: ((notification: INotification) => void) | null, context?: any | null); 32 | /** 33 | * Get the notification method. 34 | * 35 | * @returns {((notification: INotification) => void) | null} The current method or `null` if no method is set. 36 | */ 37 | get notifyMethod(): ((notification: INotification) => void) | null | undefined; 38 | /** 39 | * Set the notification method. 40 | * 41 | * The notification method should take one parameter of type `Notification`. 42 | * 43 | * @param {((notification: INotification) => void) | null} value - The method to set for handling notifications. Can be `null`. 44 | */ 45 | set notifyMethod(value: ((notification: INotification) => void) | null); 46 | /** 47 | * Get the notifyContext 48 | * 49 | * @returns {any | null} The current context or `null` if no context is set. 50 | */ 51 | get notifyContext(): any | null; 52 | /** 53 | * Set the notification context. 54 | * 55 | * @param {any | null} value - The context to set. Can be `null`. 56 | */ 57 | set notifyContext(value: any | null); 58 | /** 59 | * Notify the interested object. 60 | * 61 | * @param {INotification} notification - The notification to send to the observer. 62 | * @returns {void} 63 | */ 64 | notifyObserver(notification: INotification): void; 65 | /** 66 | * Compare an object to the notification context. 67 | * 68 | * @param {any} object - The object to compare with the observer's context. 69 | * @returns {boolean} `true` if the context is the same, otherwise `false`. 70 | */ 71 | compareNotifyContext(object: any): boolean; 72 | } 73 | -------------------------------------------------------------------------------- /bin/types/patterns/proxy/Proxy.d.ts: -------------------------------------------------------------------------------- 1 | import { IProxy } from "../../interfaces/IProxy"; 2 | import { Notifier } from "../observer/Notifier"; 3 | /** 4 | * A base `Proxy` implementation. 5 | * 6 | * In PureMVC, `Proxy` classes are used to manage parts of the 7 | * application's data model. 8 | * 9 | * A `Proxy` might simply manage a reference to a local data object, 10 | * in which case interacting with it might involve setting and 11 | * getting of its data in synchronous fashion. 12 | * 13 | * `Proxy` classes are also used to encapsulate the application's 14 | * interaction with remote services to save or retrieve data, in which case, 15 | * we adopt an asynchronous idiom; setting data (or calling a method) on the 16 | * `Proxy` and listening for a `Notification` to be sent 17 | * when the `Proxy` has retrieved the data from the service. 18 | * 19 | * @see {@link Model} 20 | * 21 | * @class Proxy 22 | * @extends Notifier 23 | */ 24 | export declare class Proxy extends Notifier implements IProxy { 25 | /** 26 | * The default name for the Proxy. 27 | * 28 | * @type {string} 29 | */ 30 | static NAME: string; 31 | /** the proxy name 32 | * @type {string} _name */ 33 | protected readonly _name: string; 34 | /** the data object 35 | * @type {any} _data */ 36 | protected _data?: any; 37 | /** 38 | * Constructor 39 | * 40 | * @param {string} [name] - The name of the proxy. Defaults to `Proxy.NAME` if not provided. 41 | * @param {any} [data] - The data associated with the proxy. Can be `null`. 42 | */ 43 | constructor(name?: string, data?: any); 44 | /** 45 | * Called by the Model when the Proxy is registered 46 | * 47 | * @returns {void} 48 | */ 49 | onRegister(): void; 50 | /** 51 | * Called by the Model when the Proxy is removed 52 | * 53 | * @returns {void} 54 | */ 55 | onRemove(): void; 56 | /** 57 | * Get the proxy name 58 | * 59 | * @returns {string} The name of the proxy. 60 | */ 61 | get name(): string; 62 | /** 63 | * Get the data object 64 | * 65 | * @returns {any} The current data or `undefined` if no data is set. 66 | */ 67 | get data(): any; 68 | /** 69 | * Set the data object 70 | * 71 | * @param {any} value - The data to set. Can be `null`. 72 | */ 73 | set data(value: any); 74 | } 75 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #795E26; 3 | --dark-hl-0: #DCDCAA; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #A31515; 7 | --dark-hl-2: #CE9178; 8 | --light-hl-3: #008000; 9 | --dark-hl-3: #6A9955; 10 | --light-hl-4: #0000FF; 11 | --dark-hl-4: #569CD6; 12 | --light-hl-5: #001080; 13 | --dark-hl-5: #9CDCFE; 14 | --light-hl-6: #267F99; 15 | --dark-hl-6: #4EC9B0; 16 | --light-code-background: #FFFFFF; 17 | --dark-code-background: #1E1E1E; 18 | } 19 | 20 | @media (prefers-color-scheme: light) { :root { 21 | --hl-0: var(--light-hl-0); 22 | --hl-1: var(--light-hl-1); 23 | --hl-2: var(--light-hl-2); 24 | --hl-3: var(--light-hl-3); 25 | --hl-4: var(--light-hl-4); 26 | --hl-5: var(--light-hl-5); 27 | --hl-6: var(--light-hl-6); 28 | --code-background: var(--light-code-background); 29 | } } 30 | 31 | @media (prefers-color-scheme: dark) { :root { 32 | --hl-0: var(--dark-hl-0); 33 | --hl-1: var(--dark-hl-1); 34 | --hl-2: var(--dark-hl-2); 35 | --hl-3: var(--dark-hl-3); 36 | --hl-4: var(--dark-hl-4); 37 | --hl-5: var(--dark-hl-5); 38 | --hl-6: var(--dark-hl-6); 39 | --code-background: var(--dark-code-background); 40 | } } 41 | 42 | :root[data-theme='light'] { 43 | --hl-0: var(--light-hl-0); 44 | --hl-1: var(--light-hl-1); 45 | --hl-2: var(--light-hl-2); 46 | --hl-3: var(--light-hl-3); 47 | --hl-4: var(--light-hl-4); 48 | --hl-5: var(--light-hl-5); 49 | --hl-6: var(--light-hl-6); 50 | --code-background: var(--light-code-background); 51 | } 52 | 53 | :root[data-theme='dark'] { 54 | --hl-0: var(--dark-hl-0); 55 | --hl-1: var(--dark-hl-1); 56 | --hl-2: var(--dark-hl-2); 57 | --hl-3: var(--dark-hl-3); 58 | --hl-4: var(--dark-hl-4); 59 | --hl-5: var(--dark-hl-5); 60 | --hl-6: var(--dark-hl-6); 61 | --code-background: var(--dark-code-background); 62 | } 63 | 64 | .hl-0 { color: var(--hl-0); } 65 | .hl-1 { color: var(--hl-1); } 66 | .hl-2 { color: var(--hl-2); } 67 | .hl-3 { color: var(--hl-3); } 68 | .hl-4 { color: var(--hl-4); } 69 | .hl-5 { color: var(--hl-5); } 70 | .hl-6 { color: var(--hl-6); } 71 | pre, code { background: var(--code-background); } 72 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE4WSQUsDMRBG/8ucF4sFRfZaEHrQCoKX0kNMpjSYzZQk2Ir0v8sqq0lmNl7z8V6W7Nt+QsJzgh5W5FMg5zBAB0eVDtCDdipGjIu/7eqQBgcdvFlvoL9e3l26X8O90sogp3/OW+SD0oFWNAzKG87na9OCxqpEwvdPS5Mmg05Ax+MW90jJ7q1WyZLneL7+b5Heflpa9OY1YniX6Glp0U+Bzh8c/T5ucc92ODqc/W3F3PK8WDxxfDxtUWt2sfUJw15pjIu1eO3y5rYU8OJLh1x9pamzzxVS+hXOq80Fcrm1oky34Hm+FSz3mzvmGxZVc88ph1wpeMm5Qq65UlQ557yQdAWXLeYs73FEd18SpZQwQQUAAA==" -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: "ts-jest", 3 | testEnvironment: "node", 4 | testMatch: ["**/?(*.)+(spec|test).ts?(x)"], 5 | maxWorkers: 11, 6 | coverageDirectory: "coverage", 7 | collectCoverage: true, 8 | collectCoverageFrom: ["src/**/*.ts"] 9 | }; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@puremvc/puremvc-typescript-multicore-framework", 3 | "version": "2.1.2", 4 | "description": "PureMVC MultiCore Framework for TypeScript", 5 | "main": "./bin/cjs/index.js", 6 | "module": "./bin/esm/index.js", 7 | "exports": { 8 | ".": { 9 | "import": { 10 | "types": "./bin/types/index.d.ts", 11 | "default": "./bin/esm/index.js" 12 | }, 13 | "require": { 14 | "types": "./bin/types/index.d.ts", 15 | "default": "./bin/cjs/index.js" 16 | } 17 | } 18 | }, 19 | "types": "./bin/types/index.d.ts", 20 | "scripts": { 21 | "build": "npm run clean && npm run build:lib && npm run build:doc", 22 | "build:lib": "npm run build:cjs && npm run build:esm", 23 | "build:esm": "tsc --module esnext --outDir bin/esm && echo '{\"type\": \"module\"}' > bin/esm/package.json && rm -rf bin/esm/interfaces", 24 | "build:cjs": "tsc --module commonjs --outDir bin/cjs && echo '{\"type\": \"commonjs\"}' > bin/cjs/package.json && rm -rf bin/cjs/interfaces", 25 | "build:doc": "typedoc", 26 | "clean": "rm -rf bin", 27 | "test": "jest --coverage", 28 | "npm:publish:dry-run": "npm publish --dry-run", 29 | "npm:publish": "npm publish --access public" 30 | }, 31 | "nyc": { 32 | "extension": [ 33 | ".ts" 34 | ], 35 | "include": [ 36 | "src/**/*.ts" 37 | ], 38 | "reporter": [ 39 | "text", 40 | "lcov" 41 | ] 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/PureMVC/puremvc-typescript-multicore-framework.git" 46 | }, 47 | "homepage": "https://puremvc.org", 48 | "bugs": { 49 | "url": "https://github.com/PureMVC/puremvc-typescript-multicore-framework/issues" 50 | }, 51 | "keywords": [ 52 | "puremvc", 53 | "typescript", 54 | "mvc" 55 | ], 56 | "files": [ 57 | "bin/**/*.*", 58 | "LICENSE", 59 | "VERSION", 60 | "package.json" 61 | ], 62 | "authors": "Saad Shams , Cliff Hall ", 63 | "license": "BSD-3-Clause", 64 | "directories": { 65 | "doc": "docs", 66 | "test": "test", 67 | "bin": "bin" 68 | }, 69 | "devDependencies": { 70 | "@types/jest": "^29.5.10", 71 | "@typescript-eslint/eslint-plugin": "^6.13.2", 72 | "@typescript-eslint/parser": "^6.13.2", 73 | "eslint": "^8.55.0", 74 | "jest": "^29.7.0", 75 | "nyc": "^17.1.0", 76 | "ts-jest": "^29.1.1", 77 | "typedoc": "^0.26.11", 78 | "typescript": "^5.6.3" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/core/Model.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Model.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IModel} from "../interfaces/IModel"; 10 | import {IProxy} from "../interfaces/IProxy"; 11 | 12 | /** 13 | * A Multiton `Model` implementation. 14 | * 15 | * In PureMVC, the `Model` class provides 16 | * access to model objects (Proxies) by named lookup. 17 | * 18 | * The `Model` assumes these responsibilities: 19 | * 20 | * - Maintain a cache of `Proxy` instances. 21 | * - Provide methods for registering, retrieving, and removing 22 | * `Proxy` instances. 23 | * 24 | * Your application must register `Proxy` instances 25 | * with the `Model`. Typically, you use an 26 | * `Command` to create and register `Proxy` 27 | * instances once the `Facade` has initialized the Core 28 | * actors. 29 | * 30 | * @see {@link Proxy} 31 | * 32 | * @class Model 33 | */ 34 | export class Model implements IModel { 35 | 36 | /** Message Constants 37 | * @type {string} */ 38 | protected static MULTITON_MSG: string = "Model instance for this Multiton key already constructed!"; 39 | 40 | /** Multiton Instances 41 | * @type {{ [key: string]: IModel }} */ 42 | protected static instanceMap: { [key: string]: IModel } = {}; 43 | 44 | /** The Multiton Key for this Core 45 | * @type {string} */ 46 | protected multitonKey: string; 47 | 48 | /** Mapping of proxyNames to IProxy instances 49 | * @type {{ [key: string]: IProxy }} */ 50 | protected proxyMap: { [key: string]: IProxy }; 51 | 52 | /** 53 | * Constructor. 54 | * 55 | * This `Model` implementation is a Multiton, 56 | * so you should not call the constructor 57 | * directly, but instead call the static Multiton 58 | * Factory method `Model.getInstance(multitonKey)` 59 | * 60 | * @param {string} key 61 | * 62 | * @throws {Error} Error if instance for this Multiton key instance has already been constructed 63 | */ 64 | public constructor(key: string) { 65 | if (Model.instanceMap[key] != null) throw Error(Model.MULTITON_MSG); 66 | this.multitonKey = key; 67 | Model.instanceMap[key] = this; 68 | this.proxyMap = {}; 69 | this.initializeModel(); 70 | } 71 | 72 | /** 73 | * Initialize the `Model` instance. 74 | * 75 | * Called automatically by the constructor, this 76 | * is your opportunity to initialize the Multiton 77 | * instance in your subclass without overriding the 78 | * constructor. 79 | * 80 | * @returns {void} 81 | */ 82 | protected initializeModel(): void { 83 | } 84 | 85 | /** 86 | * `Model` Multiton Factory method. 87 | * 88 | * @param {string} key - The key used to identify the model instance. 89 | * @param {(key: string) => IModel} factory - A factory function that creates a new instance of the model if one does not already exist for the specified key. 90 | * @returns {IModel} The model instance associated with the given key. 91 | */ 92 | public static getInstance(key: string, factory: (key: string) => IModel): IModel { 93 | if (Model.instanceMap[key] == null) 94 | Model.instanceMap[key] = factory(key); 95 | return Model.instanceMap[key]; 96 | } 97 | 98 | /** 99 | * Register a `Proxy` with the `Model`. 100 | * 101 | * @param {IProxy} proxy - The proxy instance to be registered. 102 | * @returns {void} 103 | */ 104 | public registerProxy(proxy: IProxy): void { 105 | proxy.initializeNotifier(this.multitonKey); 106 | this.proxyMap[proxy.name] = proxy; 107 | proxy.onRegister(); 108 | } 109 | 110 | /** 111 | * Retrieve a `Proxy` from the `Model`. 112 | * 113 | * @param {string} proxyName - The name of the proxy to retrieve. 114 | * @returns {IProxy | null} The proxy instance associated with the given name, or `null` if no such proxy exists. 115 | */ 116 | public retrieveProxy(proxyName: string): IProxy | null { 117 | return this.proxyMap[proxyName] || null; 118 | } 119 | 120 | /** 121 | * Check if a Proxy is registered 122 | * 123 | * @param {string} proxyName - The name of the proxy to check. 124 | * @returns {boolean} `true` if a proxy with the specified name is registered; otherwise, `false`. 125 | */ 126 | public hasProxy(proxyName: string): boolean { 127 | return this.proxyMap[proxyName] != null; 128 | } 129 | 130 | /** 131 | * Remove a `Proxy` from the `Model`. 132 | * 133 | * @param {string} proxyName - The name of the proxy to be removed. 134 | * @returns {IProxy | null} The removed proxy instance, or `null` if no proxy with the given name was found. 135 | */ 136 | public removeProxy(proxyName: string): IProxy | null { 137 | const proxy: IProxy = this.proxyMap[proxyName]; 138 | if (!proxy) return null; 139 | 140 | delete this.proxyMap[proxyName]; 141 | proxy.onRemove(); 142 | return proxy; 143 | } 144 | 145 | /** 146 | * Remove a Model instance 147 | * 148 | * @param {string} key - The key used to identify the model instance to be removed. 149 | * @returns {void} 150 | */ 151 | public static removeModel(key: string): void { 152 | delete Model.instanceMap[key]; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // index.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | export type {IController} from "./interfaces/IController"; 10 | export type {IModel} from "./interfaces/IModel"; 11 | export type {IView} from "./interfaces/IView"; 12 | export type {ICommand} from "./interfaces/ICommand"; 13 | export type {IFacade} from "./interfaces/IFacade"; 14 | export type {IMediator} from "./interfaces/IMediator"; 15 | export type {INotification} from "./interfaces/INotification"; 16 | export type {INotifier} from "./interfaces/INotifier"; 17 | export type {IObserver} from "./interfaces/IObserver"; 18 | export type {IProxy} from "./interfaces/IProxy"; 19 | 20 | export {Controller} from "./core/Controller"; 21 | export {Model} from "./core/Model"; 22 | export {View} from "./core/View"; 23 | export {MacroCommand} from "./patterns/command/MacroCommand"; 24 | export {SimpleCommand} from "./patterns/command/SimpleCommand"; 25 | export {Facade} from "./patterns/facade/Facade"; 26 | export {Mediator} from "./patterns/mediator/Mediator"; 27 | export {Notification} from "./patterns/observer/Notification"; 28 | export {Notifier} from "./patterns/observer/Notifier"; 29 | export {Observer} from "./patterns/observer/Observer"; 30 | export {Proxy} from "./patterns/proxy/Proxy"; 31 | -------------------------------------------------------------------------------- /src/interfaces/ICommand.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ICommand.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotifier} from "./INotifier"; 10 | import {INotification} from "./INotification"; 11 | 12 | /** 13 | * The interface definition for a PureMVC Command. 14 | * 15 | * @see {@link INotification} 16 | * 17 | * @interface ICommand 18 | * @extends {INotifier} 19 | */ 20 | export interface ICommand extends INotifier { 21 | /** 22 | * Execute the `ICommand`'s logic to handle a given `INotification`. 23 | * 24 | * @param {INotification} notification - The notification carrying the data and type necessary for executing the command. 25 | * @returns {void} 26 | */ 27 | execute(notification: INotification): void; 28 | } 29 | -------------------------------------------------------------------------------- /src/interfaces/IController.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IController.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {ICommand} from "./ICommand"; 10 | import {INotification} from "./INotification"; 11 | 12 | /** 13 | * `IController` The interface definition for a PureMVC `Controller`. 14 | * 15 | * In PureMVC, an `IController` implementor 16 | * follows the 'Command and Controller' strategy, and 17 | * assumes these responsibilities: 18 | * 19 | * - Remembering which `ICommands` are intended to handle which `INotifications`. 20 | * 21 | * - Registering itself as an `IObserver` with the View for each `INotification` that it has an `ICommand` mapping for. 22 | * 23 | * - Creating a new instance of the proper `ICommand` to handle a given `INotification` when notified by the `View`. 24 | * 25 | * - Calling the `ICommand`'s execute method, passing in the `INotification`. 26 | * 27 | * @interface IController 28 | */ 29 | export interface IController { 30 | /** 31 | * Register a particular `ICommand` class as the handler 32 | * for a particular INotification. 33 | * 34 | * @param {string} notificationName - the name of the `INotification` 35 | * @param {() => ICommand} factory - A factory that returns `ICommand` 36 | * @returns {void} 37 | */ 38 | registerCommand(notificationName: string, factory: () => ICommand): void; 39 | 40 | /** 41 | * Execute the `ICommand` previously registered as the 42 | * handler for `INotifications` with the given notification name. 43 | * 44 | * @param {INotification} notification - the `INotification` to execute the associated `ICommand` for 45 | * @returns {void} 46 | */ 47 | executeCommand(notification: INotification): void; 48 | 49 | /** 50 | * Check if a `Command` is registered for a given `Notification` 51 | * 52 | * @param {string} notificationName - The name of the notification to check. 53 | * @returns {boolean} `true` if a command is registered for the notification name, `false` otherwise. 54 | */ 55 | hasCommand(notificationName: string): boolean; 56 | 57 | /** 58 | * Remove a previously registered `ICommand` to `INotification` mapping. 59 | * 60 | * @param {string} notificationName - the name of the INotification to remove the ICommand mapping for 61 | * @returns {void} 62 | */ 63 | removeCommand(notificationName: string): void; 64 | } 65 | -------------------------------------------------------------------------------- /src/interfaces/IFacade.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IFacade.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotifier} from "./INotifier"; 10 | import {ICommand} from "./ICommand"; 11 | import {IMediator} from "./IMediator"; 12 | import {INotification} from "./INotification"; 13 | import {IProxy} from "./IProxy"; 14 | 15 | /** 16 | * `IFacade` The interface definition for a PureMVC `Facade`. 17 | * 18 | * The `Facade` Pattern suggests providing a single 19 | * class to act as a central point of communication 20 | * for a subsystem. 21 | * 22 | * In PureMVC, the `Facade` acts as an interface between 23 | * the core MVC actors (`Model`, `View`, `Controller`) and 24 | * the rest of your application. 25 | * 26 | * @interface IFacade 27 | * @extends {INotifier} 28 | */ 29 | export interface IFacade extends INotifier { 30 | 31 | /** 32 | * Register an `ICommand` with the `Controller` 33 | * 34 | * @param {string} notificationName - the name of the `INotification` to associate the `ICommand` with. 35 | * @param {() => ICommand} factory - A factory that creates an instance of the `ICommand` to be registered. 36 | * @returns {void} 37 | */ 38 | registerCommand(notificationName: string, factory: () => ICommand): void; 39 | 40 | /** 41 | * Check if a `ICommand` is registered for a given `Notification` 42 | * 43 | * @param {string} notificationName - The name of the notification to check. 44 | * @returns {boolean} `true` if a command is registered for the notification name, `false` otherwise. 45 | */ 46 | hasCommand(notificationName: string): boolean; 47 | 48 | /** 49 | * Remove a previously registered `ICommand` to `INotification` mapping from the `Controller`. 50 | * 51 | * @param {string} notificationName - the name of the `INotification` to remove the `ICommand` mapping for 52 | * @returns {void} 53 | */ 54 | removeCommand(notificationName: string): void; 55 | 56 | /** 57 | * Register an `IProxy` with the `Model` by name. 58 | * 59 | * @param {IProxy} proxy - the IProxy to be registered with the Model. 60 | * @returns {void} 61 | */ 62 | registerProxy(proxy: IProxy): void; 63 | 64 | /** 65 | * Retrieve a `IProxy` from the `Model` by name. 66 | * 67 | * @param {string} proxyName - the name of the `IProxy` instance to be retrieved. 68 | * @returns {IProxy | null} the `IProxy` previously registered by `proxyName` with the `Model`. 69 | */ 70 | retrieveProxy(proxyName: string): IProxy | null; 71 | 72 | /** 73 | * Check if a `Proxy` is registered 74 | * 75 | * @param {string} proxyName - The name of the proxy to check. 76 | * @returns {boolean} `true` if a proxy is registered with the name, `false` otherwise. 77 | */ 78 | hasProxy(proxyName: string): boolean; 79 | 80 | /** 81 | * Remove an `IProxy` instance from the `Model` by name. 82 | * 83 | * @param {string} proxyName - the `IProxy` to remove from the `Model`. 84 | * @returns {IProxy | null} The removed proxy instance if found, or `null` if no proxy was registered with the given name. 85 | */ 86 | removeProxy(proxyName: string): IProxy | null; 87 | 88 | /** 89 | * Register an `IMediator` instance with the `View`. 90 | * 91 | * @param {IMediator} mediator - a reference to the `IMediator` instance 92 | * @returns {void} 93 | */ 94 | registerMediator(mediator: IMediator): void; 95 | 96 | /** 97 | * Retrieve an `IMediator` instance from the `View`. 98 | * 99 | * @param {string} mediatorName - the name of the `IMediator` instance to retrieve 100 | * @returns {IMediator | null} The mediator instance if found, or `null` if no mediator is registered with the given name. 101 | */ 102 | retrieveMediator(mediatorName: string): IMediator | null; 103 | 104 | /** 105 | * Check if a `Mediator` is registered or not 106 | * 107 | * @param {string} mediatorName - The name of the mediator to check. 108 | * @returns {boolean} `true` if a mediator is registered with the name, `false` otherwise. 109 | */ 110 | hasMediator(mediatorName: string): boolean; 111 | 112 | /** 113 | * Remove a `IMediator` instance from the `View`. 114 | * 115 | * @param {string} mediatorName - The name of the mediator to remove. 116 | * @returns {IMediator | null} The removed mediator instance if found, or `null` if no mediator was registered with the given name. 117 | */ 118 | removeMediator(mediatorName: string): IMediator | null; 119 | 120 | /** 121 | * Notify Observers. 122 | * 123 | * This method is left public mostly for backward 124 | * compatibility, and to allow you to send custom 125 | * notification classes using the facade. 126 | * 127 | * Usually you should just call `sendNotification` 128 | * and pass the parameters, never having to 129 | * construct the notification yourself. 130 | * 131 | * @param {INotification} notification - the `INotification` to have the `View` notify `Observers` of. 132 | * @returns {void} 133 | */ 134 | notifyObservers(notification: INotification): void; 135 | } 136 | -------------------------------------------------------------------------------- /src/interfaces/IMediator.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IMediator.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotifier} from "./INotifier"; 10 | import {INotification} from "./INotification"; 11 | 12 | /** 13 | * `IMediator` The interface definition for a PureMVC `Mediator`. 14 | * 15 | * In PureMVC, `IMediator` implementors assume these responsibilities: 16 | * 17 | * - Implement a common method which returns a list of all `INotifications` the `IMediator` has interest in. 18 | * 19 | * - Implement a notification callback method. 20 | * 21 | * - Implement methods that are called when the `IMediator` is registered or removed from the View. 22 | * 23 | * Additionally, `IMediators` typically: 24 | * 25 | * - Act as an intermediary between one or more view components such as text boxes or list controls, maintaining references and coordinating their behavior. 26 | * 27 | * - In Flash-based apps, this is often the place where event listeners are added to view components, and their handlers implemented. 28 | * 29 | * - Respond to and generate `INotifications`, interacting with of the rest of the PureMVC app. 30 | * 31 | * When an `IMediator` is registered with the `IView`, 32 | * the `IView` will call the `IMediator`'s 33 | * `listNotificationInterests` method. The `IMediator` will 34 | * return an Array of `INotification` names which 35 | * it wishes to be notified about. 36 | * 37 | * The `IView` will then create an `Observer` object 38 | * encapsulating that `IMediator`'s (`handleNotification`) method 39 | * and register it as an `Observer` for each `INotification` name returned by 40 | * `listNotificationInterests`. 41 | * 42 | * @interface IMediator 43 | * @extends {INotifier} 44 | */ 45 | export interface IMediator extends INotifier { 46 | 47 | /** 48 | * The name of the mediator. 49 | * 50 | * @type {string} 51 | */ 52 | readonly name: string; 53 | 54 | /** 55 | * The view component associated with the mediator. 56 | * 57 | * @type {any} 58 | */ 59 | viewComponent: any; 60 | 61 | /** 62 | * Called by the View when the `Mediator` is registered 63 | * 64 | * @returns {void} 65 | */ 66 | onRegister(): void; 67 | 68 | /** 69 | * Called by the View when the `Mediator` is removed 70 | * 71 | * @returns {void} 72 | */ 73 | onRemove(): void; 74 | 75 | /** 76 | * List `INotification` interests. 77 | * 78 | * @returns {string[]} an Array of the `INotification` names this `IMediator` has an interest in. 79 | */ 80 | listNotificationInterests(): string[]; 81 | 82 | /** 83 | * Handle an `INotification`. 84 | * 85 | * @param {INotification} notification - the `INotification` to be handled 86 | * @returns {void} 87 | */ 88 | handleNotification(notification: INotification): void; 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/interfaces/IModel.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IModel.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IProxy} from "./IProxy"; 10 | 11 | /** 12 | * `IModel` The interface definition for a PureMVC `Model`. 13 | * 14 | * In PureMVC, `IModel` implementors provide 15 | * access to `IProxy` objects by named lookup. 16 | * 17 | * An `IModel` assumes these responsibilities: 18 | * 19 | * - Maintain a cache of `IProxy` instances 20 | * 21 | * - Provide methods for registering, retrieving, and removing `IProxy` instances 22 | * 23 | * @interface IModel 24 | */ 25 | export interface IModel { 26 | 27 | /** 28 | * Register an `IProxy` instance with the `Model`. 29 | * 30 | * @param {IProxy} proxy - an object reference to be held by the `Model`. 31 | * @returns {void} 32 | */ 33 | registerProxy(proxy: IProxy): void; 34 | 35 | /** 36 | * Retrieve an `IProxy` instance from the `Model`. 37 | * 38 | * @param {string} proxyName - The name of the proxy to retrieve. 39 | * @returns {IProxy | null} The `IProxy` if registered, otherwise null. 40 | */ 41 | retrieveProxy(proxyName: string): IProxy | null; 42 | 43 | /** 44 | * Check if a `Proxy` is registered 45 | * 46 | * @param {string} proxyName - The name of the proxy to check. 47 | * @returns {boolean} True if the `IProxy` is registered, otherwise false. 48 | */ 49 | hasProxy(proxyName: string): boolean; 50 | 51 | /** 52 | * Remove an `IProxy` instance from the `Model`. 53 | * 54 | * @param {string} proxyName - The name of the proxy to remove. 55 | * @returns {IProxy | null} The removed `IProxy` if found, otherwise null. 56 | */ 57 | removeProxy(proxyName: string): IProxy | null; 58 | } 59 | -------------------------------------------------------------------------------- /src/interfaces/INotification.ts: -------------------------------------------------------------------------------- 1 | // 2 | // INotification.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | /** 10 | * `INotification` The interface definition for a PureMVC `Notification`. 11 | * 12 | * PureMVC does not rely upon underlying event models such 13 | * as the one provided with Flash, and ActionScript 3 does 14 | * not have an inherent event model. 15 | * 16 | * The `Observer` Pattern as implemented within PureMVC exists 17 | * to support event-driven communication between the 18 | * application and the actors of the MVC triad. 19 | * 20 | * `Notifications` are not meant to be a replacement for Events 21 | * in Flex/Flash/AIR. Generally, `IMediator` implementors 22 | * place event listeners on their view components, which they 23 | * then handle in the usual way. This may lead to the broadcast of `Notifications` to 24 | * trigger `ICommands` or to communicate with other `IMediators`. `IProxy` and `ICommand` 25 | * instances communicate with each other and `IMediators` 26 | * by broadcasting `INotifications`. 27 | * 28 | * A key difference between Flash Events and PureMVC 29 | * `Notifications` is that Events follow the 30 | * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 31 | * until some parent component handles the Event, while 32 | * PureMVC `Notifications` follow a 'Publish/Subscribe' 33 | * pattern. PureMVC classes need not be related to each other in a 34 | * parent/child relationship in order to communicate with one another 35 | * using `Notifications`. 36 | * 37 | * @interface INotification 38 | */ 39 | export interface INotification { 40 | 41 | /** 42 | * The name of the notification. 43 | * 44 | * @type {string} 45 | */ 46 | readonly name: string; 47 | 48 | /** 49 | * The body of the notification. 50 | * 51 | * @type {any} 52 | */ 53 | body?: any; 54 | 55 | /** 56 | * The type of the notification. 57 | * 58 | * @type {string} 59 | */ 60 | type?: string; 61 | 62 | /** 63 | * Get the string representation of the `INotification` instance 64 | * 65 | * @returns {string} A string representation of the notification. 66 | */ 67 | toString(): string; 68 | } 69 | -------------------------------------------------------------------------------- /src/interfaces/INotifier.ts: -------------------------------------------------------------------------------- 1 | // 2 | // INotifier.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | /** 10 | * `INotifier` The interface definition for a PureMVC `Notifier`. 11 | * 12 | * `MacroCommand`, `Command`, `Mediator` and `Proxy` 13 | * all have a need to send `Notifications`. 14 | * 15 | * The `INotifier` interface provides a common method called 16 | * `sendNotification` that relieves implementation code of 17 | * the necessity to actually construct `Notifications`. 18 | * 19 | * The `Notifier` class, which all the above-mentioned classes 20 | * extend, also provides an initialized reference to the `Facade` 21 | * Multiton, which is required for the convenience method 22 | * for sending `Notifications`, but also eases implementation as these 23 | * classes have frequent `Facade` interactions and usually require 24 | * access to the facade anyway. 25 | * 26 | * @interface INotifier 27 | */ 28 | export interface INotifier { 29 | /** 30 | * Initialize this `INotifier` instance. 31 | * 32 | * This is how a `Notifier` get to Calls to 33 | * `sendNotification` or to access the 34 | * facade will fail until after this method 35 | * has been called. 36 | * 37 | * @param {string} key - The key used to initialize the notifier. 38 | * @returns {void} 39 | */ 40 | initializeNotifier(key: string): void; 41 | 42 | /** 43 | * Send a `INotification`. 44 | * 45 | * Convenience method to prevent having to construct new 46 | * notification instances in our implementation code. 47 | * 48 | * @param {string} notificationName - The name of the notification to send. 49 | * @param {any} [body] - Optional data associated with the notification. 50 | * @param {string} [type] - Optional type of the notification. 51 | * @returns {void} 52 | */ 53 | sendNotification(notificationName: string, body?: any, type?: string): void; 54 | } 55 | -------------------------------------------------------------------------------- /src/interfaces/IObserver.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IObserver.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotification} from "./INotification"; 10 | 11 | /** 12 | * `IObserver` The interface definition for a PureMVC `Observer`. 13 | * 14 | * In PureMVC, `IObserver` implementors assume these responsibilities: 15 | * 16 | * - Encapsulate the notification (callback) method of the interested object. 17 | * 18 | * - Encapsulate the notification context (self) of the interested object. 19 | * 20 | * - Provide methods for setting the interested object notification method and context. 21 | * 22 | * - Provide a method for notifying the interested object. 23 | * 24 | * PureMVC does not rely upon underlying event 25 | * models such as the one provided with Flash, 26 | * and ActionScript 3 does not have an inherent 27 | * event model. 28 | * 29 | * The `Observer` Pattern as implemented within 30 | * PureMVC exists to support event driven communication 31 | * between the application and the actors of the 32 | * MVC triad. 33 | * 34 | * An `Observer` is an object that encapsulates information 35 | * about an interested object with a notification method that 36 | * should be called when an `INotification` is broadcast. 37 | * The Observer then acts as a proxy for notifying the interested object. 38 | * 39 | * Observers can receive Notifications by having their 40 | * `notifyObserver` method invoked, passing 41 | * in an object implementing the `INotification` interface, such 42 | * as a subclass of `Notification`. 43 | * 44 | * @interface IObserver 45 | */ 46 | export interface IObserver { 47 | 48 | /** 49 | * The method to be called when a notification is received. 50 | * 51 | * @type {((notification: INotification) => void) | null} 52 | */ 53 | notifyMethod?: ((notification: INotification) => void) | null; 54 | 55 | /** 56 | * The context in which the notification method should be called. 57 | * 58 | * @type {any | null} 59 | */ 60 | notifyContext?: any | null; 61 | 62 | /** 63 | * Notify the interested object. 64 | * 65 | * @param {INotification} notification - the `INotification` to pass to the interested object's notification method 66 | * @returns {void} 67 | */ 68 | notifyObserver(notification: INotification): void; 69 | 70 | /** 71 | * Compare the given object to the notification context object. 72 | * 73 | * @param {any} object - The object to compare with the `notifyContext`. 74 | * @returns {boolean} `true` if the object is the same as the `notifyContext`, otherwise `false`. 75 | */ 76 | compareNotifyContext(object: any): boolean; 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/interfaces/IProxy.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IProxy.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotifier} from "./INotifier"; 10 | 11 | /** 12 | * `IProxy` The interface definition for a PureMVC `Proxy`. 13 | * 14 | * In PureMVC, `IProxy` implementors assume these responsibilities: 15 | * 16 | * - Implement a common method which returns the name of the Proxy. 17 | * 18 | * - Provide methods for setting and getting the data object. 19 | * 20 | * Additionally, `IProxy`ies typically: 21 | * 22 | * - Maintain references to one or more pieces of model data. 23 | * 24 | * - Provide methods for manipulating that data. 25 | * 26 | * - Generate `INotifications` when their model data changes. 27 | * 28 | * - Expose their name as a public static const called `NAME`, if they are not instantiated multiple times. 29 | * 30 | * - Encapsulate interaction with local or remote services used to fetch and persist model data. 31 | * 32 | * @interface IProxy 33 | * @extends INotifier 34 | */ 35 | export interface IProxy extends INotifier { 36 | 37 | /** 38 | * The name of the proxy. 39 | * 40 | * @type {string} 41 | */ 42 | readonly name: string; 43 | 44 | /** 45 | * The data associated with the proxy. 46 | * 47 | * @type {any} 48 | */ 49 | data?: any; 50 | 51 | /** 52 | * Called by the Model when the Proxy is registered 53 | * 54 | * @returns {void} 55 | */ 56 | onRegister(): void; 57 | 58 | /** 59 | * Called by the Model when the Proxy is removed 60 | * 61 | * @returns {void} 62 | */ 63 | onRemove(): void; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/interfaces/IView.ts: -------------------------------------------------------------------------------- 1 | // 2 | // IView.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IMediator} from "./IMediator"; 10 | import {INotification} from "./INotification"; 11 | import {IObserver} from "./IObserver"; 12 | 13 | /** 14 | * `IView` The interface definition for a PureMVC `View`. 15 | * 16 | * In PureMVC, the View class assumes these responsibilities: 17 | * 18 | * - Maintain a cache of `IMediator` instances. 19 | * 20 | * - Provide methods for registering, retrieving, and removing `IMediators`. 21 | * 22 | * - Managing the observer lists for each `INotification` in the application. 23 | * 24 | * - Providing a method for attaching `IObservers` to an `INotification`'s observer list. 25 | * 26 | * - Providing a method for broadcasting an `INotification`. 27 | * 28 | * - Notifying the `IObservers` of a given `INotification` when it is broadcast. 29 | * 30 | * @interface IView 31 | */ 32 | export interface IView { 33 | 34 | /** 35 | * Register an `IObserver` to be notified 36 | * of `INotifications` with a given name. 37 | * 38 | * @param {string} notificationName - The name of the notification to register the observer for. 39 | * @param {IObserver} observer - The observer to be registered. 40 | * @returns {void} 41 | */ 42 | registerObserver(notificationName: string, observer: IObserver): void; 43 | 44 | /** 45 | * Notify the `IObservers` for a particular `INotification`. 46 | * 47 | * All previously attached `IObservers` for this `INotification`'s 48 | * list are notified and are passed a reference to the `INotification` in 49 | * the order in which they were registered. 50 | * 51 | * @param {INotification} notification - the `INotification` to notify `IObservers` of. 52 | * @returns {void} 53 | */ 54 | notifyObservers(notification: INotification): void; 55 | 56 | /** 57 | * Remove a group of observers from the observer list for a given Notification name. 58 | * 59 | * @param {string} notificationName - which observer list to remove from 60 | * @param {any} notifyContext - removed the observers with this object as their `notifyContext` 61 | * @returns {void} 62 | */ 63 | removeObserver(notificationName: string, notifyContext: any): void; 64 | 65 | /** 66 | * Register an `IMediator` instance with the View. 67 | * 68 | * Registers the `IMediator` so that it can be retrieved by name, 69 | * and further interrogates the `IMediator` for its 70 | * `INotification` interests. 71 | * 72 | * If the `IMediator` returns any `INotification` 73 | * names to be notified about, an `Observer` is created encapsulating 74 | * the `IMediator` instance's `handleNotification` method 75 | * and registering it as an `Observer` for all `INotifications` the 76 | * `IMediator` is interested in. 77 | * 78 | * @param {IMediator} mediator - The `IMediator` to be registered. 79 | * @returns {void} 80 | */ 81 | registerMediator(mediator: IMediator): void; 82 | 83 | /** 84 | * Retrieve an `IMediator` from the View. 85 | * 86 | * @param {string} mediatorName - the name of the `IMediator` instance to retrieve. 87 | * @returns {IMediator | null} The `IMediator` associated with the given name, or `null` if not found. 88 | */ 89 | retrieveMediator(mediatorName: string): IMediator | null; 90 | 91 | /** 92 | * Check if a `IMediator` is registered or not 93 | * 94 | * @param {string} mediatorName - The name of the `IMediator` to check. 95 | * @returns {boolean} `true` if the `IMediator` is registered, otherwise `false`. 96 | */ 97 | hasMediator(mediatorName: string): boolean; 98 | 99 | /** 100 | * Remove an `IMediator` from the View. 101 | * 102 | * @param {string} mediatorName - name of the `IMediator` instance to be removed. 103 | * @returns {IMediator | null} The removed `IMediator`, or `null` if not found. 104 | */ 105 | removeMediator(mediatorName: string): IMediator | null; 106 | } 107 | -------------------------------------------------------------------------------- /src/patterns/command/MacroCommand.ts: -------------------------------------------------------------------------------- 1 | // 2 | // MacroCommand.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {ICommand} from "../../interfaces/ICommand"; 10 | import {INotification} from "../../interfaces/INotification"; 11 | import {SimpleCommand} from "./SimpleCommand"; 12 | 13 | /** 14 | * A base `Command` implementation that executes other `Command`s. 15 | * 16 | * A `MacroCommand` maintains a list of 17 | * `Command` Class references called `SubCommands`. 18 | * 19 | * When `execute` is called, the `MacroCommand` 20 | * instantiates and calls `execute` on each of its `SubCommands` turn. 21 | * Each `SubCommand` will be passed a reference to the original 22 | * `Notification` that was passed to the `MacroCommand`'s 23 | * `execute` method. 24 | * 25 | * Unlike `SimpleCommand`, your subclass 26 | * should not override `execute`, but instead, should 27 | * override the `initializeMacroCommand` method, 28 | * calling `addSubCommand` once for each `SubCommand` 29 | * to be executed. 30 | * 31 | * @see {@link Controller} 32 | * @see {@link Notification} 33 | * @see {@link SimpleCommand} 34 | * 35 | * @class MacroCommand 36 | * @extends Notifier 37 | */ 38 | export class MacroCommand extends SimpleCommand { 39 | 40 | /** An array of functions, each of which returns an instance of ICommand. 41 | * @type {(() => ICommand)[]} */ 42 | private subCommands: (() => ICommand)[]; 43 | 44 | /** 45 | * Constructor. 46 | * 47 | * You should not need to define a constructor, 48 | * instead, override the `initializeMacroCommand` 49 | * method. 50 | * 51 | * If your subclass does define a constructor, be 52 | * sure to call `super()`. 53 | * 54 | */ 55 | public constructor() { 56 | super(); 57 | this.subCommands = []; 58 | this.initializeMacroCommand(); 59 | } 60 | 61 | /** 62 | * Initialize the `MacroCommand`. 63 | * 64 | * In your subclass, override this method to 65 | * initialize the `MacroCommand`'s `SubCommand` 66 | * list with `Command` class references like 67 | * this: 68 | * 69 | * ```ts 70 | * // Initialize MyMacroCommand 71 | * initializeMacroCommand() { 72 | * this.addSubCommand(() => new app.FirstCommand()); 73 | * this.addSubCommand(() => new app.SecondCommand()); 74 | * this.addSubCommand(() => new app.ThirdCommand()); 75 | * } 76 | * ``` 77 | * 78 | * Note that `SubCommand`s may be any `Command` implementor, 79 | * `MacroCommand`s or `SimpleCommands` are both acceptable. 80 | */ 81 | public initializeMacroCommand(): void { 82 | 83 | } 84 | 85 | /** 86 | * Add a `SubCommand`. 87 | * 88 | * The `SubCommands` will be called in First In/First Out (FIFO) 89 | * order. 90 | * 91 | * @param {() => ICommand} factory - A factory function that creates an instance of ICommand. This function will be used to generate the sub-command. 92 | * @returns {void} 93 | */ 94 | protected addSubCommand(factory: () => ICommand): void { 95 | this.subCommands.push(factory); 96 | } 97 | 98 | /** 99 | * Execute this `MacroCommand`'s `SubCommands`. 100 | * 101 | * The `SubCommands` will be called in First In/First Out (FIFO) 102 | * order. 103 | * 104 | * @param {INotification} notification - The notification containing the data or command details to be processed. 105 | * @returns {void} 106 | */ 107 | public execute(notification: INotification): void { 108 | while (this.subCommands.length > 0) { 109 | const factory: (() => ICommand) | undefined = this.subCommands.shift(); 110 | const command: ICommand | undefined = factory?.(); 111 | if (command) { 112 | command.initializeNotifier(this.multitonKey); 113 | command.execute(notification); 114 | } 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/patterns/command/SimpleCommand.ts: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCommand.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {ICommand} from "../../interfaces/ICommand"; 10 | import {INotification} from "../../interfaces/INotification"; 11 | import {Notifier} from "../observer/Notifier"; 12 | 13 | /** 14 | * A base `Command` implementation. 15 | * 16 | * Your subclass should override the `execute` 17 | * method where your business logic will handle the `Notification`. 18 | * 19 | * @see {@link Controller} 20 | * @see {@link Notification} 21 | * @see {@link MacroCommand} 22 | * 23 | * @class SimpleCommand 24 | * @extends Notifier 25 | */ 26 | export class SimpleCommand extends Notifier implements ICommand { 27 | 28 | /** 29 | * Fulfill the use-case initiated by the given `Notification`. 30 | * 31 | * In the Command Pattern, an application use-case typically 32 | * begins with some user action, which results in a `Notification` being broadcast, which 33 | * is handled by business logic in the `execute` method of an 34 | * `Command`. 35 | * 36 | * @param {INotification} notification - The notification containing the data or command details to be processed. 37 | * @returns {void} 38 | */ 39 | public execute(notification: INotification): void { 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/patterns/mediator/Mediator.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Mediator.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IMediator} from "../../interfaces/IMediator"; 10 | import {INotification} from "../../interfaces/INotification"; 11 | import {Notifier} from "../observer/Notifier"; 12 | 13 | /** 14 | * A base `Mediator` implementation. 15 | * 16 | * @see {@link View} 17 | * 18 | * @class Mediator 19 | * @extends Notifier 20 | */ 21 | export class Mediator extends Notifier implements IMediator { 22 | 23 | /** The default name for the mediator. 24 | * @type {string} */ 25 | public static NAME: string = "Mediator"; 26 | 27 | /** the mediator name 28 | @type {string} */ 29 | protected readonly _name: string; 30 | 31 | /** The view component 32 | * @type {any} */ 33 | protected _viewComponent?: any; 34 | 35 | /** 36 | * Constructor. 37 | * 38 | * @param {string} [name] - Optional name for the mediator. Defaults to `Mediator.NAME`. 39 | * @param {any} [viewComponent] - Optional view component associated with the mediator. 40 | */ 41 | public constructor(name?: string, viewComponent?: any) { 42 | super(); 43 | this._name = name || Mediator.NAME; 44 | this._viewComponent = viewComponent; 45 | } 46 | 47 | /** 48 | * Called by the View when the Mediator is registered 49 | * 50 | * @returns {void} 51 | */ 52 | public onRegister(): void { 53 | 54 | } 55 | 56 | /** 57 | * Called by the View when the Mediator is removed 58 | * 59 | * @returns {void} 60 | */ 61 | public onRemove(): void { 62 | 63 | } 64 | 65 | /** 66 | * List the `Notification` names this 67 | * `Mediator` is interested in being notified of. 68 | * 69 | * @returns {string[]} An array of notification names. 70 | */ 71 | public listNotificationInterests(): string[] { 72 | return []; 73 | } 74 | 75 | /** 76 | * Handle `Notification`s. 77 | * 78 | * Typically, this will be handled in a switch statement, 79 | * with one 'case' entry per `Notification` 80 | * the `Mediator` is interested in. 81 | * 82 | * @param {INotification} notification - The notification to handle. 83 | * @returns {void} 84 | */ 85 | public handleNotification(notification: INotification): void { 86 | 87 | } 88 | 89 | /** 90 | * the mediator name 91 | * 92 | * @returns {string} The name of the mediator. 93 | */ 94 | public get name(): string { 95 | return this._name; 96 | } 97 | 98 | /** 99 | * Get the `Mediator`'s view component. 100 | * 101 | * Additionally, an implicit getter will usually 102 | * be defined in the subclass that casts the view 103 | * object to a type, like this: 104 | * 105 | * @returns {any} The view component. 106 | */ 107 | public get viewComponent(): any { 108 | return this._viewComponent; 109 | } 110 | 111 | /** 112 | * Set the `Mediator`'s view component. 113 | * 114 | * @param {any} value - The new view component. 115 | */ 116 | public set viewComponent(value: any) { 117 | this._viewComponent = value; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/patterns/observer/Notification.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Notification.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotification} from "../../interfaces/INotification"; 10 | 11 | /** 12 | * A base `Notification` implementation. 13 | * 14 | * PureMVC does not rely upon underlying event models such 15 | * as the one provided with Flash, and ActionScript 3 does 16 | * not have an inherent event model. 17 | * 18 | * The Observer Pattern as implemented within PureMVC exists 19 | * to support event-driven communication between the 20 | * application and the actors of the MVC triad. 21 | * 22 | * Notifications are not meant to be a replacement for Events 23 | * in Flex/Flash/Apollo. Generally, `Mediator` implementors 24 | * place event listeners on their view components, which they 25 | * then handle in the usual way. This may lead to the broadcast of `Notification`s to 26 | * trigger `Command`s or to communicate with other `Mediators`. `Proxy` and `Command` 27 | * instances communicate with each other and `Mediator`s 28 | * by broadcasting `Notification`s. 29 | * 30 | * A key difference between Flash `Event`s and PureMVC 31 | * `Notification`s is that `Event`s follow the 32 | * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy 33 | * until some parent component handles the `Event`, while 34 | * PureMVC `Notification`s follow a 'Publish/Subscribe' 35 | * pattern. PureMVC classes need not be related to each other in a 36 | * parent/child relationship in order to communicate with one another 37 | * using `Notification`s. 38 | * 39 | * @class Notification 40 | */ 41 | export class Notification implements INotification { 42 | 43 | /** the name of the notification instance 44 | * @type {string} */ 45 | private readonly _name: string; 46 | 47 | /** the body of the notification instance 48 | * @type {any} */ 49 | private _body?: any; 50 | 51 | /** 52 | * @type {string | undefined } */ 53 | private _type?: string | undefined; 54 | 55 | /** 56 | * Constructor. 57 | * 58 | * @param {string} name - The name of the notification. 59 | * @param {any} [body] - Optional data to be included with the notification. 60 | * @param {string} [type] - Optional type of the notification. 61 | */ 62 | public constructor(name: string, body?: any, type?: string) { 63 | this._name = name; 64 | this._body = body; 65 | this._type = type; 66 | } 67 | 68 | /** 69 | * Get the name of the `Notification` instance. 70 | * 71 | * @returns {string} The name of the notification. 72 | */ 73 | public get name(): string { 74 | return this._name; 75 | } 76 | 77 | /** 78 | * Get the body of the `Notification` instance. 79 | * 80 | * @returns {any} The body of the notification. 81 | */ 82 | public get body(): any { 83 | return this._body; 84 | } 85 | 86 | /** 87 | * Set the body of the `Notification` instance. 88 | * 89 | * @param {any} value - The new body to be set for the notification. 90 | */ 91 | public set body(value: any) { 92 | this._body = value; 93 | } 94 | 95 | /** 96 | * Get the type of the `Notification` instance. 97 | * 98 | * @returns {string | undefined} The type of the notification, or `undefined` if not set. 99 | */ 100 | public get type(): string | undefined { 101 | return this._type; 102 | } 103 | 104 | /** 105 | * Set the type of the `Notification` instance. 106 | * 107 | * @param {string | undefined} value - The new type to be set for the notification. 108 | */ 109 | public set type(value: string | undefined) { 110 | this._type = value; 111 | } 112 | 113 | /** 114 | * Get the string representation of the `Notification` instance. 115 | * 116 | * @returns {string} A string representation of the notification. 117 | */ 118 | public toString(): string { 119 | let msg: string = `Notification Name: ${this.name}`; 120 | msg += `\nBody: ${this.body ? this.body : "null"}`; 121 | msg += `\nType: ${this.type ?? "null"}`; 122 | return msg; 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/patterns/observer/Notifier.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Notifier.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotifier} from "../../interfaces/INotifier"; 10 | import {IFacade} from "../../interfaces/IFacade"; 11 | import {Facade} from "../facade/Facade"; 12 | 13 | /** 14 | * A Base `Notifier` implementation. 15 | * 16 | * `MacroCommand, Command, Mediator` and `Proxy` 17 | * all have a need to send `Notifications`. 18 | * 19 | * The `Notifier` interface provides a common method called 20 | * `sendNotification` that relieves implementation code of 21 | * the necessity to actually construct `Notifications`. 22 | * 23 | * The `Notifier` class, which all the above-mentioned classes 24 | * extend, provides an initialized reference to the `Facade` 25 | * Multiton, which is required for the convenience method 26 | * for sending `Notifications`, but also eases implementation as these 27 | * classes have frequent `Facade` interactions and usually require 28 | * access to the facade anyway. 29 | * 30 | * NOTE: In the MultiCore version of the framework, there is one caveat to 31 | * notifiers, they cannot send notifications or reach the facade until they 32 | * have a valid multitonKey. 33 | * 34 | * The multitonKey is set: 35 | * - on a Command when it is executed by the Controller 36 | * - on a Mediator is registered with the View 37 | * - on a Proxy is registered with the Model. 38 | * 39 | * @see {@link Proxy} 40 | * @see {@link Facade} 41 | * @see {@link Mediator} 42 | * @see {@link MacroCommand} 43 | * @see {@link SimpleCommand} 44 | * 45 | * @class Notifier 46 | */ 47 | export class Notifier implements INotifier { 48 | 49 | /** Message Constants 50 | * @type {string} */ 51 | protected static MULTITON_MSG: string = "multitonKey for this Notifier not yet initialized!"; 52 | 53 | /** The Multiton Key for this app 54 | * @type {string} */ 55 | protected multitonKey!: string; 56 | 57 | /** 58 | * Initialize this Notifier instance. 59 | * 60 | * This is how a Notifier gets its multitonKey. 61 | * Calls to sendNotification or to access the 62 | * facade will fail until after this method 63 | * has been called. 64 | * 65 | * Mediators, Commands or Proxies may override 66 | * this method in order to send notifications 67 | * or access the Multiton Facade instance as 68 | * soon as possible. They CANNOT access the facade 69 | * in their constructors, since this method will not 70 | * yet have been called. 71 | * 72 | * @param {string} key the multitonKey for this Notifier to use 73 | * @returns {void} 74 | */ 75 | public initializeNotifier(key: string): void { 76 | this.multitonKey = key; 77 | } 78 | 79 | /** 80 | * Create and send an `Notification`. 81 | * 82 | * Keeps us from having to construct new Notification 83 | * instances in our implementation code. 84 | * 85 | * @param {string} notificationName - The name of the notification to be sent. 86 | * @param {any} [body] - Optional data to be included with the notification. 87 | * @param {string} [type] - Optional type of the notification. 88 | * @returns {void} 89 | */ 90 | public sendNotification(notificationName: string, body?: any, type?: string): void { 91 | this.facade.sendNotification(notificationName, body, type); 92 | } 93 | 94 | /** 95 | * Return the Multiton Facade instance 96 | * 97 | * @returns {IFacade} The facade instance. 98 | * @throws {Error} If the multiton key is not initialized. 99 | */ 100 | public get facade(): IFacade { 101 | if (this.multitonKey == null) throw Error(Notifier.MULTITON_MSG); 102 | return Facade.getInstance(this.multitonKey, (key: string) => new Facade(key)); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/patterns/observer/Observer.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Observer.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IObserver} from "../../interfaces/IObserver"; 10 | import {INotification} from "../../interfaces/INotification"; 11 | 12 | /** 13 | * A base `Observer` implementation. 14 | * 15 | * An `Observer` is an object that encapsulates information 16 | * about an interested object with a method that should 17 | * be called when a particular `Notification` is broadcast. 18 | * 19 | * In PureMVC, the `Observer` class assumes these responsibilities: 20 | * 21 | * - Encapsulate the notification (callback) method of the interested object. 22 | * - Encapsulate the notification context (this) of the interested object. 23 | * - Provide methods for setting the notification method and context. 24 | * - Provide a method for notifying the interested object. 25 | * 26 | * @class Observer 27 | */ 28 | export class Observer implements IObserver { 29 | 30 | private _notifyMethod?: ((notification: INotification) => void) | null; 31 | 32 | private _notifyContext?: any | null; 33 | 34 | /** 35 | * Constructor. 36 | * 37 | * The notification method on the interested object should take 38 | * one parameter of type `Notification` 39 | * 40 | * @param {((notification: INotification) => void) | null} notify - The method to be called when a notification is received. Can be `null`. 41 | * @param {any | null} context - The context in which to call the `notifyMethod`. Can be `null`. 42 | */ 43 | constructor(notify?: ((notification: INotification) => void) | null, context?: any | null) { 44 | this._notifyMethod = notify; 45 | this._notifyContext = context; 46 | } 47 | 48 | /** 49 | * Get the notification method. 50 | * 51 | * @returns {((notification: INotification) => void) | null} The current method or `null` if no method is set. 52 | */ 53 | public get notifyMethod(): ((notification: INotification) => void) | null | undefined { 54 | return this._notifyMethod; 55 | } 56 | 57 | /** 58 | * Set the notification method. 59 | * 60 | * The notification method should take one parameter of type `Notification`. 61 | * 62 | * @param {((notification: INotification) => void) | null} value - The method to set for handling notifications. Can be `null`. 63 | */ 64 | public set notifyMethod(value: ((notification: INotification) => void) | null) { 65 | this._notifyMethod = value; 66 | } 67 | 68 | /** 69 | * Get the notifyContext 70 | * 71 | * @returns {any | null} The current context or `null` if no context is set. 72 | */ 73 | public get notifyContext(): any | null { 74 | return this._notifyContext; 75 | } 76 | 77 | /** 78 | * Set the notification context. 79 | * 80 | * @param {any | null} value - The context to set. Can be `null`. 81 | */ 82 | public set notifyContext(value: any | null) { 83 | this._notifyContext = value; 84 | } 85 | 86 | /** 87 | * Notify the interested object. 88 | * 89 | * @param {INotification} notification - The notification to send to the observer. 90 | * @returns {void} 91 | */ 92 | public notifyObserver(notification: INotification): void { 93 | this.notifyMethod?.call(this.notifyContext, notification); 94 | } 95 | 96 | /** 97 | * Compare an object to the notification context. 98 | * 99 | * @param {any} object - The object to compare with the observer's context. 100 | * @returns {boolean} `true` if the context is the same, otherwise `false`. 101 | */ 102 | public compareNotifyContext(object: any): boolean { 103 | return object == this.notifyContext; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/patterns/proxy/Proxy.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Proxy.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IProxy} from "../../interfaces/IProxy"; 10 | import {Notifier} from "../observer/Notifier"; 11 | 12 | /** 13 | * A base `Proxy` implementation. 14 | * 15 | * In PureMVC, `Proxy` classes are used to manage parts of the 16 | * application's data model. 17 | * 18 | * A `Proxy` might simply manage a reference to a local data object, 19 | * in which case interacting with it might involve setting and 20 | * getting of its data in synchronous fashion. 21 | * 22 | * `Proxy` classes are also used to encapsulate the application's 23 | * interaction with remote services to save or retrieve data, in which case, 24 | * we adopt an asynchronous idiom; setting data (or calling a method) on the 25 | * `Proxy` and listening for a `Notification` to be sent 26 | * when the `Proxy` has retrieved the data from the service. 27 | * 28 | * @see {@link Model} 29 | * 30 | * @class Proxy 31 | * @extends Notifier 32 | */ 33 | export class Proxy extends Notifier implements IProxy { 34 | 35 | /** 36 | * The default name for the Proxy. 37 | * 38 | * @type {string} 39 | */ 40 | public static NAME: string = "Proxy"; 41 | 42 | /** the proxy name 43 | * @type {string} _name */ 44 | protected readonly _name: string; 45 | 46 | /** the data object 47 | * @type {any} _data */ 48 | protected _data?: any; 49 | 50 | /** 51 | * Constructor 52 | * 53 | * @param {string} [name] - The name of the proxy. Defaults to `Proxy.NAME` if not provided. 54 | * @param {any} [data] - The data associated with the proxy. Can be `null`. 55 | */ 56 | public constructor(name?: string, data?: any) { 57 | super(); 58 | this._name = name || Proxy.NAME; 59 | this._data = data; 60 | } 61 | 62 | /** 63 | * Called by the Model when the Proxy is registered 64 | * 65 | * @returns {void} 66 | */ 67 | public onRegister(): void { 68 | 69 | } 70 | 71 | /** 72 | * Called by the Model when the Proxy is removed 73 | * 74 | * @returns {void} 75 | */ 76 | public onRemove(): void { 77 | 78 | } 79 | 80 | /** 81 | * Get the proxy name 82 | * 83 | * @returns {string} The name of the proxy. 84 | */ 85 | public get name(): string { 86 | return this._name; 87 | } 88 | 89 | /** 90 | * Get the data object 91 | * 92 | * @returns {any} The current data or `undefined` if no data is set. 93 | */ 94 | public get data(): any { 95 | return this._data; 96 | } 97 | 98 | /** 99 | * Set the data object 100 | * 101 | * @param {any} value - The data to set. Can be `null`. 102 | */ 103 | public set data(value: any) { 104 | this._data = value; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /test/core/ControllerTestCommand.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ControllerTestCommand.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {SimpleCommand, INotification} from "../../src"; 10 | import {ControllerTestVO} from "./ControllerTestVO"; 11 | 12 | /** 13 | * A SimpleCommand subclass used by ControllerTest. 14 | * 15 | * @see ControllerTest 16 | * @see ControllerTestVO 17 | * 18 | * @class ControllerTestCommand 19 | * @extends SimpleCommand 20 | */ 21 | export class ControllerTestCommand extends SimpleCommand { 22 | 23 | /** 24 | * Fabricate a result by multiplying the input by 2 25 | * 26 | * @param notification the note carrying the ControllerTestVO 27 | */ 28 | public override execute(notification: INotification) { 29 | const vo = notification.body as ControllerTestVO; 30 | 31 | // Fabricate a result 32 | vo.result = 2 * vo.input; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /test/core/ControllerTestCommand2.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ControllerTestCommand.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {SimpleCommand, INotification} from "../../src"; 10 | import {ControllerTestVO} from "./ControllerTestVO"; 11 | 12 | /** 13 | * A SimpleCommand subclass used by ControllerTest. 14 | * 15 | * @see ControllerTest 16 | * @see ControllerTestVO 17 | * 18 | * @class ControllerTestCommand2 19 | * @extends SimpleCommand 20 | */ 21 | export class ControllerTestCommand2 extends SimpleCommand { 22 | 23 | /** 24 | * Fabricate a result by multiplying the input by 2 and adding to the existing result 25 | * 26 | * @param {Notification} notification 27 | */ 28 | public override execute(notification: INotification): void { 29 | const vo = notification.body as ControllerTestVO; 30 | 31 | // Fabricate a result 32 | vo.result = vo.result + (2 * vo.input); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /test/core/ControllerTestVO.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ControllerTestVO.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | /** 10 | * A utility class used by ControllerTest. 11 | * 12 | * @see ControllerTest 13 | * @see ControllerTestCommand 14 | * 15 | * @class ControllerTestVO 16 | */ 17 | export class ControllerTestVO { 18 | 19 | public input: number = 0; 20 | public result: number = 0; 21 | 22 | /** 23 | * Constructor 24 | * 25 | * @param {number} input 26 | */ 27 | public constructor(input: number) { 28 | this.input = input; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/core/Model.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Model.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IModel, Model, IProxy, Proxy} from "../../src"; 10 | import {ModelTestProxy} from "./ModelTestProxy"; 11 | 12 | /** 13 | * Test the PureMVC Model class. 14 | */ 15 | describe("ModelTest", () => { 16 | 17 | /** 18 | * Tests the Model Multiton Factory Method 19 | */ 20 | test("testGetInstance", () => { 21 | // Test Factory Method 22 | const model: IModel = Model.getInstance("ModelTestKey1", (key: string) => new Model(key)); 23 | 24 | // test assertions 25 | expect(model).toBeDefined(); 26 | }); 27 | 28 | /** 29 | * Tests the proxy registration and retrieval methods. 30 | * 31 | * 32 | * Tests `registerProxy` and `retrieveProxy` in the same test. 33 | * These methods cannot currently be tested separately 34 | * in any meaningful way other than to show that the 35 | * methods do not throw exception when called. 36 | */ 37 | test("testRegisterAndRetrieveProxy", () => { 38 | // register a proxy and retrieve it. 39 | const model: IModel = Model.getInstance("ModelTestKey2", (key: string) => new Model(key)); 40 | model.registerProxy(new Proxy("colors", ["red", "green", "blue"])); 41 | const proxy: IProxy | null = model.retrieveProxy("colors"); 42 | expect(proxy).toBeDefined(); 43 | const data = proxy?.data as string[]; 44 | 45 | // test assertions 46 | expect(data).not.toBeNull(); 47 | expect(data).toBeInstanceOf(Array); 48 | expect(data.length).toBe(3); 49 | expect(data[0]).toBe("red"); 50 | expect(data[1]).toBe("green"); 51 | expect(data[2]).toBe("blue"); 52 | }); 53 | 54 | /** 55 | * Tests the proxy removal method. 56 | */ 57 | test("testRegisterAndRemoveProxy", () => { 58 | // register a proxy, remove it, then try to retrieve it 59 | const model: IModel = Model.getInstance("ModelTestKey3", (key: string) => new Model(key)); 60 | const proxy: IProxy = new Proxy("sizes", ["7", "13", "21"]); 61 | model.registerProxy(proxy); 62 | 63 | // remove the proxy 64 | const removedProxy: IProxy | null = model.removeProxy("sizes"); 65 | 66 | // assert that we removed the appropriate proxy 67 | expect(removedProxy).not.toBeNull(); 68 | expect(removedProxy?.name).toBe("sizes"); 69 | 70 | // ensure that the proxy is no longer retrievable from the model 71 | const proxy1 = model.retrieveProxy("sizes"); 72 | 73 | // test assertions 74 | expect(proxy1).toBeNull(); 75 | }); 76 | 77 | /** 78 | * Tests the hasProxy Method 79 | */ 80 | test("testHasProxy", () => { 81 | // register a proxy 82 | const model: IModel = Model.getInstance("ModelTestKey4", (key: string) => new Model(key)); 83 | const proxy: IProxy = new Proxy("aces", ["clubs", "spades", "hearts", "diamonds"]); 84 | model.registerProxy(proxy); 85 | 86 | // assert that the model.hasProxy method returns true 87 | // for that proxy name 88 | expect(model.hasProxy("aces")).toBeTruthy(); 89 | 90 | // remove the proxy 91 | model.removeProxy("aces"); 92 | 93 | // assert that the model.hasProxy method returns false 94 | // for that proxy name 95 | expect(model.hasProxy("aces")).toBeFalsy(); 96 | }); 97 | 98 | /** 99 | * Tests that the Model calls the onRegister and onRemove methods 100 | */ 101 | test("testOnRegisterAndOnRemove", () => { 102 | // Get a Multiton Model instance 103 | const model: IModel = Model.getInstance("ModelTestKey5", (key: string) => new Model(key)); 104 | 105 | // Create and register the test proxy 106 | const proxy: IProxy = new ModelTestProxy(); 107 | model.registerProxy(proxy); 108 | 109 | // assert that onRegister was called, and the proxy responded by setting its data accordingly 110 | expect(proxy.data).toBe(ModelTestProxy.ON_REGISTER_CALLED); 111 | 112 | // Remove the component 113 | model.removeProxy(ModelTestProxy.NAME); 114 | 115 | // assert that onRemove was called, and the proxy responded by setting its data accordingly 116 | expect(proxy.data).toBe(ModelTestProxy.ON_REMOVE_CALLED); 117 | }); 118 | 119 | // Test for constructor with an existing key 120 | test("testModelConstructorWithExistingKeyThrowsError", () => { 121 | const key = "ExistingModelKey"; 122 | Model.getInstance(key, k => new Model(k)); 123 | 124 | expect(() => new Model(key)).toThrow("Model instance for this Multiton key already constructed!"); 125 | }); 126 | 127 | // Test for removing a proxy twice 128 | test("testRemoveProxyTwice", () => { 129 | const model: IModel = Model.getInstance("ModelTestKeyTwice", k => new Model(k)); 130 | 131 | const proxy: IProxy = new Proxy("testProxy", {}); 132 | model.registerProxy(proxy); 133 | 134 | const removedProxy = model.removeProxy("testProxy"); 135 | expect(removedProxy).toBe(proxy); 136 | 137 | const secondRemovedProxy = model.removeProxy("testProxy"); 138 | expect(secondRemovedProxy).toBeNull(); 139 | }); 140 | 141 | }); 142 | -------------------------------------------------------------------------------- /test/core/ModelTestProxy.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ModelTestProxy.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Proxy} from "../../src"; 10 | 11 | /** 12 | * @class ModelTestProxy 13 | * @extends Proxy 14 | */ 15 | export class ModelTestProxy extends Proxy { 16 | 17 | public static NAME: string = "ModelTestProxy"; 18 | public static ON_REGISTER_CALLED: string = "OnRegisterCalled"; 19 | public static ON_REMOVE_CALLED: string = "OnRemoveCalled"; 20 | 21 | public constructor() { 22 | super(ModelTestProxy.NAME, ""); 23 | } 24 | 25 | public override onRegister(): void { 26 | this.data = ModelTestProxy.ON_REGISTER_CALLED; 27 | } 28 | 29 | public override onRemove(): void { 30 | this.data = ModelTestProxy.ON_REMOVE_CALLED; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /test/core/ViewTestMediator.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestMediator.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Mediator} from "../../src"; 10 | 11 | /** 12 | * A Mediator class used by ViewTest. 13 | * 14 | * @class ViewTestMediator 15 | * @extends Mediator 16 | */ 17 | export class ViewTestMediator extends Mediator { 18 | 19 | public static NAME = "ViewTestMediator"; 20 | 21 | /** 22 | * @param {any} view 23 | */ 24 | public constructor(view: any) { 25 | super(ViewTestMediator.NAME, view); 26 | } 27 | 28 | public override listNotificationInterests(): string[] { 29 | // be sure that the mediator has some Observers created 30 | // in order to test removeMediator 31 | return ["ABC", "DEF", "GHI"]; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /test/core/ViewTestMediator2.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestMediator2.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotification, Mediator} from "../../src"; 10 | import {ViewTestNote} from "./ViewTestNote"; 11 | 12 | /** 13 | * @class ViewTestMediator2 14 | * @extends Mediator 15 | */ 16 | export class ViewTestMediator2 extends Mediator { 17 | 18 | public static NAME: string = "ViewTestMediator2"; 19 | 20 | /** 21 | * Constructor 22 | * 23 | * @constructor 24 | * @param view 25 | */ 26 | public constructor(view: any) { 27 | super(ViewTestMediator2.NAME, view); 28 | } 29 | 30 | /** 31 | * @override 32 | * @returns {[string]} 33 | */ 34 | public override listNotificationInterests(): string[] { 35 | return [ViewTestNote.NOTE1, ViewTestNote.NOTE2]; 36 | } 37 | 38 | /** 39 | * @override 40 | * @param notification 41 | */ 42 | public override handleNotification(notification: INotification) { 43 | this.viewComponent.lastNotification = notification.name; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /test/core/ViewTestMediator3.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestMediator3.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Mediator, INotification} from "../../src"; 10 | import {ViewTestNote} from "./ViewTestNote"; 11 | 12 | /** 13 | * @class ViewTestMediator3 14 | * @extends Mediator 15 | */ 16 | export class ViewTestMediator3 extends Mediator { 17 | 18 | public static NAME: string = "ViewTestMediator3"; 19 | 20 | /** 21 | * @constructor 22 | * @param {object} view 23 | */ 24 | public constructor(view: any) { 25 | super(ViewTestMediator3.NAME, view); 26 | } 27 | 28 | public listNotificationInterests(): string[] { 29 | // be sure that the mediator has some Observers created 30 | // in order to test removeMediator 31 | return [ViewTestNote.NOTE3]; 32 | } 33 | 34 | /** 35 | * @override 36 | * @param notification 37 | */ 38 | handleNotification(notification: INotification) { 39 | this.viewComponent.lastNotification = notification.name; 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/core/ViewTestMediator4.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestMediator4.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Mediator} from "../../src"; 10 | 11 | /** 12 | * @class ViewTestMediator4 13 | * @extends Mediator 14 | */ 15 | export class ViewTestMediator4 extends Mediator { 16 | 17 | public static NAME: string = "ViewTestMediator4"; 18 | 19 | /** 20 | * Constructor 21 | * @param {Object} view 22 | */ 23 | public constructor(view: any) { 24 | super(ViewTestMediator4.NAME, view); 25 | } 26 | 27 | /** 28 | * @override 29 | */ 30 | public onRegister() { 31 | this.viewComponent.onRegisterCalled = true; 32 | } 33 | 34 | /** 35 | * @override 36 | */ 37 | public onRemove() { 38 | this.viewComponent.onRemoveCalled = true; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/core/ViewTestMediator5.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestMediator5.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Mediator, INotification} from "../../src"; 10 | import {ViewTestNote} from "./ViewTestNote"; 11 | 12 | /** 13 | * @class ViewTestMediator5 14 | * @extends Mediator 15 | */ 16 | export class ViewTestMediator5 extends Mediator { 17 | 18 | public static NAME: string = "ViewTestMediator5"; 19 | 20 | /** 21 | * 22 | * @param {Object} view 23 | */ 24 | public constructor(view: any) { 25 | super(ViewTestMediator5.NAME, view); 26 | } 27 | 28 | /** 29 | * @override 30 | * @returns {[string]} 31 | */ 32 | public override listNotificationInterests(): string[] { 33 | return [ViewTestNote.NOTE5]; 34 | } 35 | 36 | /** 37 | * @override 38 | * @param {Notification} notification 39 | */ 40 | public override handleNotification(notification: INotification): void { 41 | this.viewComponent.counter++; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /test/core/ViewTestMediator6.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestMediator6.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Mediator, INotification} from "../../src"; 10 | import {ViewTestNote} from "./ViewTestNote"; 11 | 12 | /** 13 | * @class ViewTestMediator6 14 | * @extends Mediator 15 | */ 16 | export class ViewTestMediator6 extends Mediator { 17 | 18 | public static NAME: string = "ViewTestMediator6"; 19 | 20 | public constructor(name: string, view: any) { 21 | super(name, view); 22 | } 23 | 24 | public override listNotificationInterests(): string[] { 25 | return [ViewTestNote.NOTE6]; 26 | } 27 | 28 | public handleNotification(notification: INotification) { 29 | this.facade.removeMediator(this.name); 30 | } 31 | 32 | public override onRemove() { 33 | this.viewComponent.counter++; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /test/core/ViewTestNote.ts: -------------------------------------------------------------------------------- 1 | // 2 | // ViewTestNote.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Notification} from "../../src"; 10 | 11 | export class ViewTestNote extends Notification { 12 | 13 | public static NAME: string = "ViewTestNote"; 14 | 15 | public static NOTE1: string = "Notification1"; 16 | public static NOTE2: string = "Notification2"; 17 | public static NOTE3: string = "Notification3"; 18 | public static NOTE4: string = "Notification4"; 19 | public static NOTE5: string = "Notification5"; 20 | public static NOTE6: string = "Notification6"; 21 | 22 | /** 23 | * 24 | * @param {string} name 25 | * @param {Object} body 26 | */ 27 | public constructor(name: string, body: any) { 28 | super(name, body); 29 | } 30 | 31 | /** 32 | * 33 | * @param {Object} body 34 | * @returns {ViewTestNote} 35 | */ 36 | public static create(body: any): Notification { 37 | return new ViewTestNote(ViewTestNote.NAME, body); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /test/patterns/command/MacroCommand.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // MacroCommand.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import { MacroCommand } from "../../../src"; 10 | import { Notification } from "../../../src"; 11 | 12 | /** 13 | * Test the PureMVC MacroCommand class. 14 | * 15 | * @see MacroCommand 16 | */ 17 | describe("MacroCommandTest", () => { 18 | 19 | test("testExecuteWithUndefinedSubCommand", () => { 20 | class TestMacroCommand extends MacroCommand { 21 | public initializeMacroCommand(): void { 22 | this.addSubCommand(undefined as any); // intentionally adding undefined 23 | } 24 | } 25 | 26 | const macroCommand = new TestMacroCommand(); 27 | const notification = new Notification("TestNotification"); 28 | 29 | // Call execute and ensure it handles the undefined command gracefully 30 | expect(() => macroCommand.execute(notification)).not.toThrow(); 31 | 32 | // Since the subcommand was undefined, no ICommand should be executed, thus, nothing to assert on command effects 33 | // Additional assertions might include verifying that no state was changed 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/patterns/command/MacroCommandTestVO.ts: -------------------------------------------------------------------------------- 1 | // 2 | // MacroCommandTestVO.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | /** 10 | * A utility class used by MacroCommandTest. 11 | * 12 | * @see MacroCommandTest 13 | * @see MacroCommandTestCommand 14 | * @see MacroCommandTestSub1Command 15 | * @see MacroCommandTestSub2Command 16 | * 17 | * @class MacroCommandTestVO 18 | */ 19 | export class MacroCommandTestVO { 20 | 21 | public input: number; 22 | public result1: number | undefined; 23 | public result2: number | undefined; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param {number} input the number to be fed to the MacroCommandTestCommand 29 | */ 30 | constructor(input: number) { 31 | this.input = input; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /test/patterns/command/SimpleCommand.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCommand.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Notification} from "../../../src"; 10 | import {SimpleCommandTestVO} from "./SimpleCommandTestVO"; 11 | import {SimpleCommandTestCommand} from "./SimpleCommandTestCommand"; 12 | 13 | /** 14 | * Test the PureMVC SimpleCommand class. 15 | * 16 | * @see SimpleCommandTestVO 17 | * @see SimpleCommandTestCommand 18 | */ 19 | describe("SimpleCommandTest", () => { 20 | 21 | /** 22 | * Tests the `execute` method of a `SimpleCommand`. 23 | * 24 | * This test creates a new `Notification`, adding a 25 | * `SimpleCommandTestVO` as the body. 26 | * It then creates a `SimpleCommandTestCommand` and invokes 27 | * its `execute` method, passing in the note. 28 | * 29 | * Success is determined by evaluating a property on the 30 | * object that was passed on the Notification body, which will 31 | * be modified by the SimpleCommand. 32 | */ 33 | test("testSimpleCommandExecute", () => { 34 | // Create the VO 35 | const vo = new SimpleCommandTestVO(5); 36 | 37 | // Create the Notification (note) 38 | const notification = new Notification("SimpleCommandTestNote", vo); 39 | 40 | // Create the SimpleCommand 41 | const command = new SimpleCommandTestCommand(); 42 | 43 | // Execute the SimpleCommand 44 | command.execute(notification); 45 | 46 | // test assertions 47 | expect(vo.result).toBe(10); 48 | 49 | }); 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /test/patterns/command/SimpleCommandTestCommand.ts: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCommandTestCommand.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {SimpleCommand, INotification} from "../../../src"; 10 | import {SimpleCommandTestVO} from "./SimpleCommandTestVO"; 11 | 12 | /** 13 | * A SimpleCommand subclass used by SimpleCommandTest. 14 | * 15 | * @class SimpleCommandTestCommand 16 | * @extends SimpleCommand 17 | */ 18 | export class SimpleCommandTestCommand extends SimpleCommand { 19 | 20 | /** 21 | * Fabricate a result by multiplying the input by 2 22 | * 23 | * @param {Notification} notification event the `INotification` carrying the `SimpleCommandTestVO` 24 | */ 25 | execute(notification: INotification): void { 26 | const vo: SimpleCommandTestVO = notification.body as SimpleCommandTestVO; 27 | 28 | // Fabricate a result 29 | vo.result = vo.input * 2; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /test/patterns/command/SimpleCommandTestVO.ts: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCommandTestVO.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | /** 10 | * A utility class used by SimpleCommandTest. 11 | * 12 | * @see SimpleCommandTest 13 | * @see SimpleCommandTestCommand 14 | * 15 | * @class SimpleCommandTestVO 16 | */ 17 | export class SimpleCommandTestVO { 18 | 19 | public input: number; 20 | public result: number | undefined; 21 | 22 | /** 23 | * Constructor. 24 | * 25 | * @param {number} input the number to be fed to the SimpleCommandTestCommand 26 | */ 27 | public constructor(input: number) { 28 | this.input = input; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/patterns/facade/Facade.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Facade.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Facade, IProxy, Proxy, Mediator} from "../../../src"; 10 | import {FacadeTestCommand} from "./FacadeTestCommand"; 11 | import {FacadeTestVO} from "./FacadeTestVO"; 12 | 13 | /** 14 | * Test the PureMVC Facade class. 15 | * 16 | * @see FacadeTestVO 17 | * @see FacadeTestCommand 18 | */ 19 | describe("FacadeTest", () => { 20 | 21 | // Test for duplicate Facade instance 22 | test("testFacadeConstructorWithExistingKeyThrowsError", () => { 23 | const key = "DuplicateFacadeKey"; 24 | Facade.getInstance(key, k => new Facade(k)); 25 | 26 | expect(() => new Facade(key)).toThrowError("Facade instance for this Multiton key already constructed!"); 27 | }); 28 | 29 | // Test initialization indirectly through function 30 | test("testInitializeComponents", () => { 31 | const facade = Facade.getInstance("ComponentInitKey", k => new Facade(k)); 32 | 33 | // Using public methods indirectly 34 | facade.registerProxy(new Proxy("testProxy", {})); 35 | expect(facade.hasProxy("testProxy")).toBe(true); 36 | 37 | facade.registerCommand("testCommand", () => new FacadeTestCommand()); 38 | expect(facade.hasCommand("testCommand")).toBe(true); 39 | }); 40 | 41 | // Test command registration and execution 42 | test("testRegisterAndExecuteCommandViaFacade", () => { 43 | const facade = Facade.getInstance("CommandViaFacadeKey", k => new Facade(k)); 44 | 45 | facade.registerCommand("TestNote", () => new FacadeTestCommand()); 46 | const vo = new FacadeTestVO(10); 47 | facade.sendNotification("TestNote", vo); 48 | 49 | expect(vo.result).toBe(20); 50 | }); 51 | 52 | // Test proxy management 53 | test("testProxyManagement", () => { 54 | const facade = Facade.getInstance("ProxyManagementKey", k => new Facade(k)); 55 | 56 | const proxy: IProxy = new Proxy("myProxy", {data: "test"}); 57 | facade.registerProxy(proxy); 58 | expect(facade.retrieveProxy("myProxy")).toBe(proxy); 59 | 60 | // Test hasProxy 61 | expect(facade.hasProxy("myProxy")).toBe(true); 62 | 63 | // Remove and test 64 | facade.removeProxy("myProxy"); 65 | expect(facade.retrieveProxy("myProxy")).toBe(null); 66 | }); 67 | 68 | // Test mediator management 69 | test("testMediatorManagement", () => { 70 | const facade = Facade.getInstance("MediatorManagementKey", k => new Facade(k)); 71 | 72 | const mediator: Mediator = new Mediator("myMediator", {}); 73 | facade.registerMediator(mediator); 74 | expect(facade.retrieveMediator("myMediator")).toBe(mediator); 75 | 76 | // Test hasMediator 77 | expect(facade.hasMediator("myMediator")).toBe(true); 78 | 79 | // Remove and test 80 | facade.removeMediator("myMediator"); 81 | expect(facade.retrieveMediator("myMediator")).toBe(null); 82 | }); 83 | 84 | // Test core management 85 | test("testHasCoreAndRemoveCore", () => { 86 | const key = "CoreManagementKey"; 87 | Facade.getInstance(key, k => new Facade(k)); 88 | 89 | expect(Facade.hasCore(key)).toBe(true); 90 | 91 | Facade.removeCore(key); 92 | 93 | expect(Facade.hasCore(key)).toBe(false); 94 | }); 95 | 96 | }); 97 | -------------------------------------------------------------------------------- /test/patterns/facade/FacadeTestCommand.ts: -------------------------------------------------------------------------------- 1 | // 2 | // FacadeTestCommand.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {SimpleCommand, INotification} from "../../../src"; 10 | import {FacadeTestVO} from "./FacadeTestVO"; 11 | 12 | /** 13 | * A SimpleCommand subclass used by FacadeTest. 14 | * 15 | * @see FacadeTest 16 | * @see FacadeTestVO 17 | * 18 | * @class FacadeTestCommand 19 | * @extends SimpleCommand 20 | */ 21 | export class FacadeTestCommand extends SimpleCommand { 22 | 23 | /** 24 | * Fabricate a result by multiplying the input by 2 25 | * 26 | * @param {Notification} notification the Notification carrying the FacadeTestVO 27 | */ 28 | public override execute(notification: INotification): void { 29 | const vo: FacadeTestVO = notification.body as FacadeTestVO; 30 | 31 | // Fabricate a result 32 | vo.result = vo.input * 2; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /test/patterns/facade/FacadeTestVO.ts: -------------------------------------------------------------------------------- 1 | // 2 | // FacadeTestVO.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | /** 10 | * A utility class used by FacadeTest. 11 | * 12 | * @class FacadeTestVO 13 | */ 14 | export class FacadeTestVO { 15 | 16 | public input: number; 17 | public result: number = 0; 18 | 19 | 20 | /** 21 | * @constructor 22 | * @param {number} input the number to be fed to the FacadeTestCommand 23 | */ 24 | public constructor(input: number) { 25 | this.input = input; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /test/patterns/mediator/Mediator.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Mediator.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IMediator, Mediator} from "../../../src"; 10 | 11 | /** 12 | * Test the PureMVC Mediator class. 13 | * 14 | * @see IMediator 15 | * @see Mediator 16 | */ 17 | describe("MediatorTest", () => { 18 | 19 | /** 20 | * Tests getting the name using Mediator class accessor method. 21 | */ 22 | test("testNameAccessor", () => { 23 | // Create a new Mediator and use accessors to set the mediator name 24 | const mediator: IMediator = new Mediator(); 25 | 26 | // test assertions 27 | expect(mediator.name).toBe(Mediator.NAME); 28 | }); 29 | 30 | /** 31 | * Tests getting the name using Mediator class accessor method. 32 | */ 33 | test("testViewAccessor", () => { 34 | // Create a view object 35 | const view: object = {}; 36 | 37 | // Create a new Proxy and use accessors to set the proxy name 38 | const mediator: IMediator = new Mediator(Mediator.NAME, view); 39 | 40 | // test assertions 41 | expect(mediator.viewComponent).toBe(view); 42 | }); 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /test/patterns/observer/Notification.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Notification.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotification, Notification} from "../../../src"; 10 | 11 | /** 12 | * Test the PureMVC Notification class. 13 | * 14 | * @see Notification1 15 | */ 16 | describe("NotificationTest", () => { 17 | 18 | /** 19 | * Tests setting and getting the name using Notification class accessor methods. 20 | */ 21 | test("testNameAccessors", () => { 22 | // Create a new Notification and use accessors to set the note name 23 | const notification: INotification = new Notification("TestNote"); 24 | 25 | // test assertions 26 | expect(notification.name).toBe("TestNote"); 27 | }); 28 | 29 | /** 30 | * Tests setting and getting the body using Notification class accessor methods. 31 | */ 32 | test("testBodyAccessors", () => { 33 | // Create a new Notification and use accessors to set the body 34 | const notification: INotification = new Notification("TestNote"); 35 | notification.body = 5; 36 | 37 | // test assertions 38 | expect(notification.body).toBe(5); 39 | }); 40 | 41 | /** 42 | * Tests setting the name and body using the Notification class Constructor. 43 | */ 44 | test("testConstructor", () => { 45 | // Create a new Notification using the Constructor to set the note name and body 46 | const notification: INotification = new Notification("TestNote", 5, "TestNoteType"); 47 | 48 | // test assertions 49 | expect(notification.name).toBe("TestNote"); 50 | expect(notification.body).toBe(5); 51 | expect(notification.type).toBe("TestNoteType"); 52 | }); 53 | 54 | /** 55 | * Tests the toString method of the notification 56 | */ 57 | test("testToString", () => { 58 | // Create a new Notification and use accessors to set the note name 59 | const notification: INotification = new Notification("TestNote", [1, 3, 5], "TestType"); 60 | const ts = "Notification Name: TestNote\nBody: 1,3,5\nType: TestType"; 61 | 62 | // test assertions 63 | expect(notification.toString()).toBe(ts); 64 | }); 65 | 66 | }); 67 | -------------------------------------------------------------------------------- /test/patterns/observer/Notifier.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Notifier.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {Facade, Notifier} from "../../../src"; 10 | import {FacadeTestVO} from "../facade/FacadeTestVO"; 11 | import {FacadeTestCommand} from "../facade/FacadeTestCommand"; 12 | 13 | /** 14 | * Test the PureMVC Notifier class. 15 | * 16 | * @see Facade 17 | */ 18 | describe("NotifierTest", () => { 19 | 20 | test("test", () => { 21 | const facade = Facade.getInstance("notifierTest", (key: string) => new Facade(key)); 22 | 23 | expect(Facade.hasCore("notifierTest")).toBeTruthy(); 24 | 25 | const vo = new FacadeTestVO(5); 26 | facade.registerCommand("testCommand", () => new FacadeTestCommand()); 27 | 28 | const notifier = new Notifier(); 29 | notifier.initializeNotifier("notifierTest"); 30 | notifier.sendNotification("testCommand", vo); 31 | 32 | // test assertions 33 | expect(vo.result).toBe(10); 34 | }); 35 | 36 | // Test accessing facade before initialization 37 | test("testAccessFacadeBeforeInitializationThrowsError", () => { 38 | const notifier = new Notifier(); 39 | 40 | expect(() => { 41 | // Attempt to access facade before calling initializeNotifier 42 | console.log(notifier.facade); 43 | }).toThrow("multitonKey for this Notifier not yet initialized!"); 44 | }); 45 | 46 | }); 47 | -------------------------------------------------------------------------------- /test/patterns/observer/Observer.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Observer.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {INotification, Notification, Observer} from "../../../src"; 10 | 11 | /** 12 | * Tests PureMVC Observer class. 13 | * 14 | * Since the Observer encapsulates the interested object's 15 | * callback information, there are no getters, only setters. 16 | * It is, in effect write-only memory. 17 | * 18 | * Therefore, the only way to test it is to set the 19 | * notification method and context and call the notifyObserver 20 | * method. 21 | */ 22 | describe("ObserverTest", () => { 23 | 24 | let observerTestVar: number = -1; 25 | 26 | const observerTestMethod = (notification: INotification): void => { 27 | observerTestVar = notification.body; 28 | }; 29 | 30 | /** 31 | * Tests observer class when initialized by accessor methods. 32 | */ 33 | test("testObserverAccessors", () => { 34 | // Create observer with null args, then 35 | // use accessors to set notification method and context 36 | const observer = new Observer(null, null); 37 | observer.notifyContext = this; 38 | observer.notifyMethod = observerTestMethod; 39 | 40 | // create a test event, setting a payload value and notify 41 | // the observer with it. since the observer is this class 42 | // and the notification method is observerTestMethod, 43 | // successful notification will result in our local 44 | // observerTestVar being set to the value we pass in 45 | // on the note body. 46 | const notification: INotification = new Notification("ObserverTestNote", 10); 47 | observer.notifyObserver(notification); 48 | 49 | // test assertions 50 | expect(observerTestVar).toBe(10); 51 | }); 52 | 53 | /** 54 | * Tests observer class when initialized by constructor. 55 | */ 56 | test("testObserverConstructor", () => { 57 | // Create observer with null args, then 58 | // use accessors to set notification method and context 59 | const observer = new Observer(observerTestMethod, this); 60 | 61 | // create a test note, setting a body value and notify 62 | // the observer with it. since the observer is this class 63 | // and the notification method is observerTestMethod, 64 | // successful notification will result in our local 65 | // observerTestVar being set to the value we pass in 66 | // on the note body. 67 | const notification: INotification = new Notification("ObserverTestNote", 5); 68 | observer.notifyObserver(notification); 69 | 70 | // test assertions 71 | expect(observerTestVar).toBe(5); 72 | }); 73 | 74 | /** 75 | * Tests the compareNotifyContext method of the Observer class 76 | */ 77 | test("testCompareNotifyContext", () => { 78 | // Create observer passing in notification method and context 79 | const observer = new Observer(observerTestMethod, this); 80 | const negTestObject: object = {}; 81 | 82 | // test assertions 83 | expect(observer.compareNotifyContext(negTestObject)).toBe(false); 84 | expect(observer.compareNotifyContext(this)).toBe(true); 85 | }); 86 | 87 | /** 88 | * Tests notifyObserver with undefined notifyMethod 89 | */ 90 | test("testNotifyObserverWithUndefinedNotifyMethod", () => { 91 | const context = { name: "Sample Context" }; 92 | 93 | // Initialize Observer without a notification method 94 | const observer = new Observer(undefined, context); 95 | 96 | // Create a sample notification 97 | const notification = new Notification("TestNotification"); 98 | 99 | // Call notifyObserver and ensure no error is thrown 100 | expect(() => observer.notifyObserver(notification)).not.toThrow(); 101 | }); 102 | 103 | }); 104 | -------------------------------------------------------------------------------- /test/patterns/proxy/Proxy.spec.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Proxy.spec.ts 3 | // PureMVC TypeScript Multicore 4 | // 5 | // Copyright(c) 2024 Saad Shams 6 | // Your reuse is governed by the BSD-3-Clause License 7 | // 8 | 9 | import {IProxy, Proxy} from "../../../src"; 10 | 11 | /** 12 | * Test the PureMVC Proxy class. 13 | * 14 | * @see IProxy 15 | * @see Proxy 16 | */ 17 | describe("ProxyTest", () => { 18 | 19 | /** 20 | * Tests getting the name using Proxy class accessor method. Setting can only be done in constructor. 21 | */ 22 | test("testNameAccessor", () => { 23 | // Create a new Proxy and use accessors to set the proxy name 24 | const proxy: IProxy = new Proxy("TestProxy"); 25 | 26 | // test assertions 27 | expect(proxy.name).toBe("TestProxy"); 28 | 29 | const proxy2 = new Proxy(); 30 | 31 | // test assertions 32 | expect(proxy2.name).toBe(Proxy.NAME); 33 | }); 34 | 35 | /** 36 | * Tests setting and getting the data using Proxy class accessor methods. 37 | */ 38 | test("testDataAccessors", () => { 39 | // Create a new Proxy and use accessors to set the data 40 | const proxy = new Proxy("colors"); 41 | proxy.data = ["red", "green", "blue"]; 42 | const data = proxy.data; 43 | 44 | // test assertions 45 | expect(data.length).toBe(3); 46 | expect(data[0]).toBe("red"); 47 | expect(data[1]).toBe("green"); 48 | expect(data[2]).toBe("blue"); 49 | }); 50 | 51 | /** 52 | * Tests setting the name and body using the Notification class Constructor. 53 | */ 54 | test("testConstructor", () => { 55 | // Create a new Proxy using the Constructor to set the name and data 56 | const proxy = new Proxy("colors", ["red", "green", "blue"]); 57 | const data = proxy.data; 58 | 59 | // test assertions 60 | expect(data.length).toBe(3); 61 | expect(data[0]).toBe("red"); 62 | expect(data[1]).toBe("green"); 63 | expect(data[2]).toBe("blue"); 64 | }); 65 | 66 | }); 67 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "moduleResolution": "node", 5 | "strict": true, 6 | "declaration": true, 7 | "declarationDir": "bin/types", 8 | "esModuleInterop": true, 9 | "skipLibCheck": true 10 | }, 11 | "include": ["src/**/*"], 12 | "exclude": ["docs", "node_modules", "bin", "test"], 13 | "typedocOptions": { 14 | "entryPoints": ["src/index.ts"], 15 | "out": "docs" 16 | } 17 | } 18 | --------------------------------------------------------------------------------