-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* init * fix test * ci * wip * working * working * test * readme * ci * update * upd * fix * fix * tags * version
- Loading branch information
1 parent
7741c0b
commit a88aae5
Showing
19 changed files
with
3,945 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
{ | ||
"root": true, | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": ["@typescript-eslint"], | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/eslint-recommended", | ||
"plugin:@typescript-eslint/recommended" | ||
], | ||
"rules": { | ||
"no-magic-numbers": "off", | ||
"no-console": ["warn", { "allow": ["warn", "error"] }], | ||
"no-warning-comments": [ | ||
"warn", | ||
{ | ||
"terms": ["TODO"], | ||
"location": "start" | ||
} | ||
], | ||
"no-alert": "warn", | ||
"no-duplicate-imports": ["error", { "includeExports": true }], | ||
"no-unused-private-class-members": "error", | ||
"camelcase": "error", | ||
"eqeqeq": "error", | ||
"@typescript-eslint/member-ordering": "error", | ||
"arrow-body-style": ["error", "as-needed"], | ||
"prefer-const": "error", | ||
"@typescript-eslint/no-unused-vars": [ | ||
"error", | ||
{ | ||
"args": "all", | ||
"argsIgnorePattern": "^_", | ||
"caughtErrors": "all", | ||
"caughtErrorsIgnorePattern": "^_", | ||
"destructuredArrayIgnorePattern": "^_", | ||
"varsIgnorePattern": "^_", | ||
"ignoreRestSiblings": true | ||
} | ||
], | ||
"lines-between-class-members": [ | ||
"error", | ||
{ | ||
"enforce": [ | ||
{ "blankLine": "always", "prev": "*", "next": "method" }, | ||
{ "blankLine": "always", "prev": "method", "next": "*" }, | ||
{ "blankLine": "always", "prev": "field", "next": "field" } | ||
] | ||
}, | ||
{ "exceptAfterSingleLine": true } | ||
], | ||
"@typescript-eslint/no-non-null-assertion": "warn", | ||
"no-fallthrough": "error", | ||
"object-shorthand": ["error", "always"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Create tag | ||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
permissions: | ||
contents: write | ||
|
||
jobs: | ||
build-createTag: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
|
||
- name: Setup Node | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: "20.x" | ||
|
||
- name: Install dependencies | ||
run: yarn setup | ||
|
||
- name: Lint | ||
run: yarn lint | ||
|
||
- name: Test | ||
run: yarn test | ||
|
||
- name: Build | ||
run: yarn build | ||
|
||
- name: Create Tag | ||
run: yarn createTag | ||
env: | ||
GH_TOKEN: ${{ secrets.GHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: Build and Test | ||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
lint-build-test: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
|
||
- name: Setup Node | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: "20.x" | ||
|
||
- name: Install dependencies | ||
run: yarn setup | ||
|
||
- name: Lint | ||
run: yarn lint | ||
|
||
- name: Test | ||
run: yarn test | ||
|
||
- name: Build | ||
run: yarn build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
name: Release | ||
on: | ||
release: | ||
types: [published] | ||
|
||
jobs: | ||
build-release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
- name: Setup Node | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: "20.x" | ||
registry-url: https://registry.npmjs.org/ | ||
- name: Install dependencies | ||
run: yarn setup | ||
|
||
- name: Lint | ||
run: yarn lint | ||
|
||
- name: Test | ||
run: yarn test | ||
|
||
- name: Build | ||
run: yarn build | ||
|
||
- name: Publish | ||
run: npm publish | ||
env: | ||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
dist | ||
yarn-error.log | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"arrowParens": "avoid" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# ts-mixin | ||
|
||
[![Minified Size](https://badgen.net/bundlephobia/min/ts-mixin)](https://bundlephobia.com/result?p=ts-mixin) | ||
|
||
## Overview | ||
|
||
`ts-mixin` is a lightweight TypeScript Mixin framework. The Mixin pattern is meant to add reusable functionality to objects without any class inheritance ([source](https://www.patterns.dev/vanilla/mixin-pattern/)). | ||
|
||
### Features | ||
|
||
- Intuitive way to create Mixins for easy integration into existing systems | ||
- Strong type-safety during compilation, along with runtime safety while creating and initializing the Mixins | ||
- Provides inter-class reusability of attributes (props/methods) by passing the _mixed_ object to the initializer (constructor) | ||
|
||
## 🏁 Getting started | ||
|
||
``` | ||
$ npm install ts-mixin | ||
// OR | ||
$ yarn add ts-mixin | ||
``` | ||
|
||
## 💡 Quick start | ||
|
||
A `Bank` system where the core functionality is _mixed_ in from various existing classes like `Amount` and `Deposit`: | ||
|
||
```typescript | ||
import { BaseMixin } from "ts-mixin"; | ||
|
||
type IAmount = { | ||
amount: number; | ||
setAmount: (newAmount: number) => void; | ||
}; | ||
|
||
// Basic class to manage the amount | ||
class Amount implements IAmount { | ||
public amount: number = 1000; | ||
|
||
constructor(private readonly bank: IBank) {} | ||
|
||
public setAmount(newAmount: number): void { | ||
this.amount = newAmount; | ||
} | ||
} | ||
|
||
// Define the Amount Mixin | ||
class AmountMixin extends BaseMixin<IBank, IAmount> { | ||
constructor() { | ||
super({ | ||
// Specify the methods and props to be be mixed | ||
methods: ["setAmount"], | ||
props: ["amount"], | ||
initMixin: bank => new Amount(bank), | ||
}); | ||
} | ||
} | ||
``` | ||
|
||
```typescript | ||
import { BaseMixin } from "ts-mixin"; | ||
|
||
type IDeposit = { | ||
deposit: (amount: number) => void; | ||
}; | ||
|
||
// Basic class to deposit money into the account | ||
class Deposit implements IDeposit { | ||
constructor(private readonly bank: IBank) {} | ||
|
||
public deposit(depositAmount: number): void { | ||
this.bank.setAmount(this.bank.amount + depositAmount); | ||
} | ||
} | ||
|
||
// Define the Deposit Mixin | ||
class DepositMixin extends BaseMixin<IBank, IDeposit> { | ||
constructor() { | ||
super({ | ||
// Specify the methods and props to be be mixed | ||
methods: ["deposit"], | ||
props: [], | ||
initMixin: bank => new Deposit(bank), | ||
}); | ||
} | ||
} | ||
``` | ||
|
||
Define the `IBank` interface to represent the Mixed object based on the above Mixins: | ||
|
||
```typescript | ||
type IBank = IAmount & IDeposit; | ||
``` | ||
|
||
Create the mixed `bank` object using an input list of Mixin implementations: | ||
|
||
```typescript | ||
import { mix } from "ts-mixin"; | ||
|
||
const bank = mix<IBank>({ | ||
mixins: [new AmountMixin(), new DepositMixin()], | ||
}); | ||
|
||
// Complete type-safety for the mixed object | ||
console.log(bank.amount); // 1000 | ||
bank.deposit(500); | ||
console.log(bank.amount); // 500 | ||
bank.setAmount(2000); | ||
console.log(bank.amount); // 2000 | ||
``` | ||
|
||
Runtime safety is guaranteed while mixing objects in the following scenarios: | ||
|
||
- Attempting to bind a method as a prop and vice versa | ||
- Attempting to bind a prop/method that already exists on the object | ||
|
||
## ✏️ Contributing | ||
|
||
- Post any issues and suggestions on the GitHub [issues](https://github.com/hasnainroopawalla/ts-mixin/issues) page. | ||
- To contribute, fork the project and then create a pull request back to `main`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"transform": { | ||
"^.+\\.(t|j)sx?$": "ts-jest" | ||
}, | ||
"testRegex": "\\.test\\.[jt]sx?$", | ||
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"], | ||
"testEnvironment": "jsdom" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "ts-mixin", | ||
"version": "0.0.1", | ||
"description": "A lightweight TypeScript Mixin framework.", | ||
"repository": "https://github.com/hasnainroopawalla/ts-mixin", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"setup": "yarn install --ignore-scripts", | ||
"build": "tsc", | ||
"prepare": "yarn build", | ||
"publish:dry-run": "npm publish --dry-run", | ||
"test": "jest --config jestconfig.json", | ||
"test:watch": "jest --config jestconfig.json --watch", | ||
"lint": "eslint \"{**/*,*}.{js,ts,jsx,tsx}\"", | ||
"createTag": "PACKAGE_VERSION=$(cat package.json | grep \\\"version\\\" | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d '[[:space:]]') && git tag v$PACKAGE_VERSION && git push --tags" | ||
}, | ||
"files": [ | ||
"dist", | ||
"LICENSE", | ||
"README.md" | ||
], | ||
"keywords": ["typescript", "mixin", "mixins", "oop", "generics", "runtime"], | ||
"author": "Hasnain Roopawalla", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@types/jest": "^29.5.12", | ||
"@typescript-eslint/eslint-plugin": "^8.2.0", | ||
"@typescript-eslint/parser": "^8.2.0", | ||
"eslint": "^8.48.0", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"ts-jest": "^29.2.5", | ||
"tslib": "^2.7.0", | ||
"typescript": "^5.5.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { BindUtils } from "./bind-utils"; | ||
|
||
type IBaseMixinArgs<TBase, TMixin> = { | ||
props: Array<keyof TMixin>; | ||
methods: Array<keyof TMixin>; | ||
initMixin: (base: TBase) => TMixin; | ||
}; | ||
|
||
export class BaseMixin<TBase, TMixin> { | ||
private args: IBaseMixinArgs<TBase, TMixin>; | ||
|
||
constructor(args: IBaseMixinArgs<TBase, TMixin>) { | ||
this.args = args; | ||
} | ||
|
||
public initMixin(base: TBase): void { | ||
const mixin = this.args.initMixin(base); | ||
|
||
BindUtils.bindMethods(base, mixin, this.args.methods); | ||
BindUtils.bindProps(base, mixin, this.args.props); | ||
} | ||
} |
Oops, something went wrong.