diff --git a/.github/wip.yml b/.github/wip.yml new file mode 100644 index 0000000..95c7bb4 --- /dev/null +++ b/.github/wip.yml @@ -0,0 +1,8 @@ +- locations: title + terms: + - DMG + - ⛔ +- terms: + - 🚧 + - WIP + locations: title diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml new file mode 100644 index 0000000..aad552a --- /dev/null +++ b/.github/workflows/pr-ci.yml @@ -0,0 +1,38 @@ +name: PR CI + +on: + pull_request: + push: + branches: + - main + +jobs: + verify: + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.10 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run lint + run: bun run lint + + - name: Check formatting + run: bun run fmt:check + + - name: Run typecheck + run: bun run typecheck + + - name: Run tests + run: bun run test + + - name: Build package + run: bun run build diff --git a/.oxfmt.json b/.oxfmt.json index b21d27d..3329432 100644 --- a/.oxfmt.json +++ b/.oxfmt.json @@ -8,5 +8,5 @@ "endOfLine": "lf", "bracketSpacing": true, "arrowParens": "always", - "ignorePatterns": ["dist/**"] + "ignorePatterns": ["dist/**", "*.json"] } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 061671a..bc111c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,11 +17,13 @@ This repository is focused on a small, explicit DI core for standard ECMAScript This repository uses Lefthook. - `pre-commit` runs fast staged-file checks for lint and formatting. +- hooks are contributor-local and are not installed for package consumers. -If hooks stop working locally, reinstall them with `bun run hooks:install`. +Install or reinstall them locally with `bun run hooks:install`. ## Pull request checklist +- PR CI runs lint, format, typecheck, test, and build checks automatically. - the change is focused and documented; - scripts in the local checks section pass; - package exports and Node compatibility were kept intact; diff --git a/README.md b/README.md index 938598d..f4461a3 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,17 @@ No environment variables or external services are required for local development ## Public entry points -The package root currently exports: +The package root currently exports runtime values and TypeScript types. + +Runtime exports: - `Container` - `Service` - `Inject` +- `Token` + +Type-only exports: + - `Constructable` / `AbstractConstructable` - `ServiceIdentifier` @@ -126,10 +132,16 @@ Current behavior: ## Decorators -### `@Service(options?)` +### `@Service(idOrOptions?)` Registers a class in the default container. +Accepted forms today: + +- `@Service()` +- `@Service(id)` +- `@Service({ id, scope })` + Options supported today: - `id?: ServiceIdentifier` @@ -146,7 +158,8 @@ class LoggerService {} const logger = Container.of().get('logger'); ``` -Note: a custom string id works for manual resolution through `container.get(...)`, but `@Inject()` currently accepts a constructable class dependency rather than an arbitrary token. +Custom identifiers work for both `container.get(...)` and `@Inject(...)`. +When you use `Token` instances, resolution is based on object identity, so create the token once and reuse the same instance everywhere. ### `@Inject(dependency)` @@ -161,6 +174,35 @@ Current characteristics: - injected fields are defined as writable and configurable own properties on the created instance; - injected fields are assigned after construction, so they are not available inside constructors or field initializers. +Token example: + +```ts +import { Container, Inject, Service, Token } from 'navi-di'; + +interface Logger { + log(message: string): void; +} + +const LOGGER = new Token('Logger'); + +@Service(LOGGER) +class ConsoleLogger implements Logger { + public log(message: string) { + console.log(message); + } +} + +@Service() +class HandlerService { + @Inject(LOGGER) + public logger!: Logger; +} + +const handler = Container.of().get(HandlerService); + +handler.logger.log('hello from token injection'); +``` + ## Container API ### `Container.of(id?)` @@ -193,6 +235,13 @@ Supported strategies: This is especially useful in tests. +### `container.set(metadata)` + +Registers or replaces service metadata for a service identifier. + +This is a low-level API that powers manual registration scenarios and internal tests. +For application-facing code, prefer `@Service()` unless you specifically need to construct metadata yourself. + ## Internal architecture The implementation is intentionally small and split into a few focused modules: @@ -242,9 +291,9 @@ What they do: - `lint`: run `oxlint` with warnings denied - `fmt`: format the repository with `oxfmt` - `fmt:check`: verify formatting without writing changes -- `hooks:*`: install, validate, or run the Lefthook-based Git hooks +- `hooks:*`: install, validate, or run the repo-local Lefthook Git hooks -`bun install` also triggers `postinstall`, which installs the local Git hooks automatically. +Git hooks are optional and repo-local. After cloning, contributors can install them with `bun run hooks:install`. Current note: `typecheck` uses `tsconfig.json` with `noEmit: true`, while `build` uses `tsconfig.build.json` with `noEmit: false` to emit `dist/` and declaration files. @@ -255,7 +304,8 @@ The repository currently enforces: - strict TypeScript checking; - `oxlint` for linting; - `oxfmt` for formatting; -- Lefthook `pre-commit` checks for staged TypeScript, JavaScript, Markdown, YAML, and YML files. +- PR CI checks for lint, format, typecheck, tests, and build; +- optional Lefthook `pre-commit` checks for staged TypeScript, JavaScript, Markdown, YAML, and YML files. The package `prepack` script runs lint, format check, typecheck, and build before publishing. diff --git a/package.json b/package.json index a23aee5..f1258c0 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "navi-di", "version": "0.1.0", "description": "Dependency injection for standard ECMAScript decorators.", + "author": "naviary-sanctuary", "keywords": [ "bun", "decorators", @@ -51,7 +52,6 @@ "lint": "oxlint . --deny-warnings", "fmt": "oxfmt --config .oxfmt.json .", "fmt:check": "oxfmt --check --config .oxfmt.json .", - "postinstall": "lefthook install", "prepack": "bun run lint && bun run fmt:check && bun run typecheck && bun run build", "test": "bun test --pass-with-no-tests" },