Skip to content

Commit

Permalink
Merge pull request #1 from mrmilu/refactor-and-publish
Browse files Browse the repository at this point in the history
Refactor and publish
  • Loading branch information
hazzo committed Aug 7, 2023
2 parents 4b99411 + d6a8b96 commit fcee9f2
Show file tree
Hide file tree
Showing 44 changed files with 4,760 additions and 653 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-typescript"]
}
23 changes: 23 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"plugins": ["@typescript-eslint", "unused-imports"],
"extends": [
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"unused-imports/no-unused-imports": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/array-type": [
"error",
{
"default": "generic",
"readonly": "generic"
}
]
},
"settings": {
"react": {
"version": "detect"
}
}
}
66 changes: 66 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Release

on:
workflow_dispatch:
push:
branches: [main]

jobs:
release-and-docs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.BOT_ACCESS_TOKEN }}

- name: git config user
run: |
git config --global user.name mrm-dev
git config --global user.email [email protected]
- name: Setup Node.js environment
uses: actions/[email protected]
with:
node-version: "18"

- name: Install dependencies
run: |
corepack enable
pnpm install
- name: Release
run: |
pnpm release
git push --follow-tags origin master
pnpm build
- name: Publish
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
package: "./package.json"

- name: Set env for last tag release
run: echo "LAST_TAG=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV

- name: Post to a Slack channel
id: slack
uses: slackapi/[email protected]
with:
channel-id: "C0BJB6V4P"
payload: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":robot_face: New Inversify Generator release :robot_face:\n*<https://github.com/mrmilu/inversify_generator/blob/master/CHANGELOG.md|${{ env.LAST_TAG }}>*"
}
}
]
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
node_modules
out
build
build
dist
.idea
.DS_Store
4 changes: 4 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit ""
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
3 changes: 3 additions & 0 deletions .lintstagedrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
"**/*": [() => "pnpm check-types", () => "pnpm lint", "prettier --write --ignore-unknown"]
};
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
7 changes: 7 additions & 0 deletions .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
printWidth: 150
tabWidth: 2
semi: true
singleQuote: false
trailingComma: "none"
bracketSpacing: true
arrowParens: "always"
3 changes: 3 additions & 0 deletions .versionrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
releaseCommitMessageFormat: "chore(release): [skip ci] {{currentTag}}"
};
134 changes: 109 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,129 @@
# IoC Generator
# Inversify Generator

Generates the boilerplate code for an IoC container. Used for dependency injection config.
[Inversify](https://github.com/inversify/InversifyJS) it's a great inversion of control container for TypeScript.
But due to the nature of TypeScript and the inability to infer types at runtime Inversify and every other
IoC for TypeScript relies on identifiers to assign an implementation to an abstraction.

## Configuration options
This packages tries to make the process of assigning an identifier to an implementation a little
less cumbersome by generating type identifiers and bindings for inversify automatically.

| Option | Description | Default |
| ---------- | ---------------------------- | ----------------- |
| `tsconfig` | Path to the tsconfig file | `./tsconfig.json` |
| `out` | Path to the output directory | `./src/ioc` |
## Install

These configuration options can be passed as command line arguments in the POSIX format, e.g. `--tsconfig ./tsconfig.json`.
```shell
yarn install inversify-generator
```

## Usage

First you must configure the generator settings.

There are two ways, through command flags or through a `inversify-generator.json`
config file.

### Options

| Option | Description | Default |
| ---------- | ------------------------------------------------------------------------ | ----------------- |
| `tsconfig` | Path to the tsconfig file | `./tsconfig.json` |
| `output` | Path to the output directory | `./src/ioc` |
| `binding` | Type of binding applied to the<br/>implementations in the generated file | `default` |
| `watch` | Watch files for binding and types generation | `false` |

The configuration options can also be set in the `ioc-boilerplate-generator.json` config file, which is optional and must be located in the root directory of the project. The command line arguments take precedence over the config file. This is an example config file:
Type `inversify-generator -h` to see a list of available flags and how to use them.

`inversify-generator.json` config file example:

```json
{
"tsconfig": "./tsconfig.json",
"out": "./src/ioc"
"output": "./src/ioc",
"binding": "default"
}
```

## Usage
### Binding type

One of the configuration options it's `binding`. This configuration has two possibilities:
`default` or `dynamic`.

The `default` will generate the bindings in a simple manner directly to the container
as stated in inversify documentation:

Example of generated file with this binding:

```typescript
import { Container } from "inversify";
import { TYPES } from "./types";
import { Ninja } from "./entities/ninja";
import { Katana } from "./entities/katana";
import { Shuriken } from "./entities/shuriken";

const myContainer = new Container();
myContainer.bind(TYPES.Warrior).to(Ninja);
myContainer.bind(TYPES.Weapon).to(Katana);
myContainer.bind(TYPES.ThrowableWeapon).to(Shuriken);

```bash
nvm use # Sets the correct node version
corepack enable # Enables pnpm
pnpm install # Installs dependencies
mkdir out # Creates output directory
pnpm run dev # Runs program
export { myContainer };
```

## Dependencies
On the other hand the `dynamic` type will use a util exposed by this package that
binds implementations with [dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import)
adding the possibility of creating [providers (asynchronous factories)](https://github.com/inversify/InversifyJS/blob/master/wiki/provider_injection.md).

- `ts-morph`: Typescript AST analyser
- `yargs`: Command line arguments parser
If you are using inversify in a front end app, this method will probably make
your main bundle smaller (as long as the sections that load the async factories are not executed)
because it will only download the corresponding dependency chunks when needed.

This would be an example of the generated file by the `dynamic` binding type:

```typescript
import { Container } from "inversify";
import { TYPES } from "./types";
import { bindDynamicModule } from "inversify-generator/utils";

const myContainer = new Container();
bindDynamicModule(TYPES.Warrior, () => import("./entities/ninja"), locator.bind);
bindDynamicModule(TYPES.Weapon, () => import("./entities/katana"), locator.bind);
bindDynamicModule(TYPES.ThrowableWeapon, () => import("./entities/shuriken"), locator.bind);

export { myContainer };
```

> **IMPORTANT**
> Using `dynamic` binding has the current limitation that the function only binds the
> first exported module of the file. Meaning, if you have more than one class exported
> in the file and decorated with `@injectable` only the first one will be bound. So if you
> are using the `dynamic` type try having one class implementation per file.
### Decorator util

This package also has a decorator util that will let you handle per dependency both scope and binding type.
By default, Inversify when binding a dependency it does it with the **transient** scope. With this util you will able
to configure the scope per dependency to be either **transient** or **singleton**.

Also, this decorator adds the ability to configure the [binding type](#binding-type) per dependency so that if you have one
default binding configured ([through flag or config file](#options)) you can select another one to a specific class.

```typescript
import { generatorConf } from "inversify-generator/decorators";

@injectable()
@generatorConf({ scope: "singleton", biding: "default" })
export class FooRepository implements IFooRepository {
@inject(TYPES.Service) private serviceProvider!: IocProvider<IService>;

async baz(): Promise<Page<Post>> {
const service = await this.serviceProvider();
const baz = await service.get<Array<Record<string, unknown>>>("/baz");
return baz.data;
}
}
```

## Roadmap

- [x] Implement syntax analysis
- [x] Implement IoC boilerplate generation
- [x] Add command line arguments to configure the paths of the tsconfig file and the output directory.
- [x] Refactor code
- [ ] Add `request` scope for configuration decorator.
- [ ] Add support for modules
- [ ] Add tests
- [ ] Publish to npm
- [ ] Add possibility to have several exported modules in a file to use
with the `dynamic` binding method.
2 changes: 2 additions & 0 deletions bin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require("./generator");
6 changes: 6 additions & 0 deletions commitlint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"header-max-length": [2, "always", 120]
}
};
4 changes: 4 additions & 0 deletions decorators/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"main": "dist/inversify-generator-decorators.cjs.js",
"module": "dist/inversify-generator-decorators.esm.js"
}
4 changes: 4 additions & 0 deletions generator/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"main": "dist/inversify-generator-generator.cjs.js",
"module": "dist/inversify-generator-generator.esm.js"
}
4 changes: 0 additions & 4 deletions ioc-boilerplate-generator.json

This file was deleted.

6 changes: 0 additions & 6 deletions nodemon.json

This file was deleted.

Loading

0 comments on commit fcee9f2

Please sign in to comment.