Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: Bug report
about: Something isn't working as documented
title: 'fix: <short description>'
labels: bug
assignees: brmorillo
---

## Describe the bug

<!-- A clear and concise description of what the bug is. -->

## Module / method

<!-- e.g. CryptUtils.aesEncrypt, SortUtils.quickSort -->

## Steps to reproduce

```ts
// Minimal reproduction
import { } from '@brmorillo/utils';

```

## Expected behavior

<!-- What should have happened. -->

## Actual behavior

<!-- What actually happened. Include the full error message and stack trace if applicable. -->

## Environment

- `@brmorillo/utils` version:
- Node.js version:
- Runtime (Node / Bun / browser):
- Module format used (`require` / `import`):

## Additional context

<!-- Anything else that might help — related issues, workarounds tried, etc. -->
34 changes: 34 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: Feature request
about: Propose a new method, module, or additive improvement
title: 'feat: <short description>'
labels: enhancement
assignees: brmorillo
---

## Problem / motivation

<!-- What problem does this solve? What use-case is missing? -->

## Proposed API

```ts
// Show how the new method / module would be called.
// Follow the single-object-argument convention used by the rest of the library.
import { } from '@brmorillo/utils';

```

## Alternatives considered

<!-- Have you tried to solve this with existing methods? What other approaches did you evaluate? -->

## Scope and compatibility notes

<!-- v14 is API-frozen: only additive, non-breaking changes are accepted.
Breaking changes require a new major version.
Does your proposal add new methods / optional params, or does it change existing signatures? -->

## Additional context

<!-- Links to related issues, prior art, or reference implementations. -->
35 changes: 35 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Summary

<!-- What does this PR do? 1-3 bullet points. -->

-
-

## Type of change

- [ ] Bug fix (`fix:`)
- [ ] New feature / additive change (`feat:`)
- [ ] Documentation (`docs:`)
- [ ] Refactor — no behavior change (`refactor:`)
- [ ] Tests (`test:`)
- [ ] CI / tooling (`chore:`, `ci:`)
- [ ] Performance (`perf:`)
- [ ] Breaking change (`feat!:` / `fix!:` + `BREAKING CHANGE:` footer)

## Checklist

- [ ] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, …)
- [ ] `bun run type-check` passes
- [ ] `bun run lint` passes (0 warnings)
- [ ] `CI=true bun run test:ci` passes (coverage thresholds met)
- [ ] `bun run build` passes with 0 warnings
- [ ] New public methods have TSDoc (`/** */` with at least a summary line)
- [ ] No `throw new Error(…)` — typed errors from `src/errors` only
- [ ] Data-transforming methods are non-mutating by default (add `inPlace?` if mutation is needed)
- [ ] No ESM-only runtime dependencies added (check `require` export before bumping a major)

## Test plan

<!-- How did you verify this works? Which test files cover it? -->

-
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.

## [14.1.1](https://github.com/brmorillo/util/compare/v14.1.0...v14.1.1) (2026-06-17)


### Documentation

* add CI badge, CONTRIBUTING.md, PR template and issue templates ([e6b8b9b](https://github.com/brmorillo/util/commit/e6b8b9b0482cbe26edd8f277ccf330fa1832b132))

## [14.1.0](https://github.com/brmorillo/util/compare/v14.0.2...v14.1.0) (2026-06-17)


Expand Down
160 changes: 160 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Contributing to @brmorillo/utils

Thank you for taking the time to contribute! This document is a quick-start guide. For the full architecture and convention reference, read [CLAUDE.md](./CLAUDE.md).

## Table of contents

- [Getting started](#getting-started)
- [Development workflow](#development-workflow)
- [Conventions](#conventions)
- [Adding a new method](#adding-a-new-method)
- [Adding a new module](#adding-a-new-module)
- [Commit and branch naming](#commit-and-branch-naming)
- [Pull request process](#pull-request-process)
- [Dependency policy](#dependency-policy)

---

## Getting started

```bash
git clone https://github.com/brmorillo/utils.git
cd utils
bun install # npm install fails here — use bun
bun run build # typecheck + CJS + ESM + .d.ts
CI=true bun run test:ci # full suite with coverage gate
```

> **Node.js >= 18** and **[Bun](https://bun.sh)** are required.

---

## Development workflow

```bash
bun run type-check # tsc --noEmit
bun run lint # eslint (0 warnings expected)
bun run test # jest unit + integration
bun run test:coverage
bun run build # must finish with 0 warnings
bun run format # prettier --write src/
```

All five commands must pass before opening a PR.

---

## Conventions

These are enforced by CI and the invariant test suites — a PR that breaks them will not be merged.

### Single object argument

Every static utility method takes **one destructured object**:

```ts
// ✅
StringUtils.toCamelCase({ input: 'hello world' })

// ❌
StringUtils.toCamelCase('hello world')
```

Singleton services (`HttpService`, `LogService`, `StorageService`) use a method-style API instead — that is intentional.

### Non-mutating by default

Data-transforming methods must return a **new value** and leave the input untouched. Where in-place mutation makes sense, expose it as `inPlace?: boolean` (default `false`). See `immutability.spec.ts` and `inplace-invariant.spec.ts`.

### Typed errors only

**Never** `throw new Error(…)` in library code. Use the typed errors from `src/errors`:

```ts
import { ValidationError, BaseError, StorageError, HttpError, QueueFullError } from '../errors';

throw new ValidationError('Input must be a string', 'input');
throw new BaseError('Something went wrong', 'MY_ERROR_CODE', 500, details, { cause: err });
```

### TSDoc on every public member

All exported classes, methods, constructors, and helpers need a `/** */` block with at least a summary line.

### Predicate naming

- Property predicates: `is*` (`isEven`, `isPrime`, `isPalindrome`)
- Format validators in `ValidationUtils`: `isValid*` (`isValidEmail`, `isValidCPF`)

### English only

All identifiers, comments, doc strings, and test descriptions must be in English.

---

## Adding a new method

1. Add the static method to the appropriate service in `src/services/`.
2. Write a TSDoc block for it.
3. Add unit tests in `tests/unit/<module>.service.spec.ts`.
4. Add an integration test in `tests/integration/<module>.service.int-spec.ts`.
5. If the method is data-transforming, add it to `immutability.spec.ts`. If it supports `inPlace`, add it to `inplace-invariant.spec.ts`.
6. Update the module docs in `docs/<module>/README.md`.

---

## Adding a new module

1. Create `src/services/<name>.service.ts` with a static utility class.
2. Export it from `src/index.ts`.
3. Add unit + integration tests.
4. Add it to `tests/unit/public-surface.spec.ts` and `tests/integration/contract.int-spec.ts`.
5. Create `docs/<name>/README.md` and link it from `docs/README.md` and `README.md`.

---

## Commit and branch naming

This project uses [Conventional Commits](https://www.conventionalcommits.org/):

| Type | When to use |
| --- | --- |
| `feat:` | New method, module, or additive export |
| `fix:` | Bug fix |
| `docs:` | Documentation only |
| `refactor:` | Internal restructure, no behavior change |
| `test:` | Adding or fixing tests |
| `chore:` | Build, config, tooling |
| `ci:` | CI workflow changes |
| `perf:` | Performance improvement |

Breaking changes: add `!` suffix (`feat!:`) and include a `BREAKING CHANGE:` footer.

Branch naming: `feature/<name>`, `fix/<issue>`, `docs/<topic>`, `chore/<task>`.

---

## Pull request process

1. Open a PR against `main`.
2. The `pr-version` workflow automatically commits a `chore(release): vX.Y.Z` bump to your branch — **do not edit it manually**.
3. The CI pipeline (type-check → lint → test with coverage → build → secret scan) must pass.
4. A maintainer reviews and merges. After merge, the `release` workflow tags and publishes to npm automatically.

---

## Dependency policy

- All dependencies are pinned to **exact versions** (no `^` or `~`).
- Updates happen **once a month**, staying **at least 3 months behind** the latest release (supply-chain safety buffer).
- Before bumping a runtime dependency to a new major, verify it ships a CommonJS build:
```bash
node -e "require('<package>')"
```
- `uuid` is permanently pinned to `^11` and `@paralleldrive/cuid2` to `^2` (v3+ are ESM-only and would break CJS consumers).

---

## Questions?

Open a [GitHub Discussion](https://github.com/brmorillo/utils/issues) or reach out via [bruno@rmorillo.com](mailto:bruno@rmorillo.com).
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# @brmorillo/utils

[![npm version](https://badge.fury.io/js/@brmorillo%2Futils.svg)](https://www.npmjs.com/package/@brmorillo/utils)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
[![License: LGPL-3.0](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
[![npm version](https://img.shields.io/npm/v/@brmorillo/utils?label=npm&color=cb3837)](https://www.npmjs.com/package/@brmorillo/utils)
[![CI](https://github.com/brmorillo/utils/actions/workflows/ci.yml/badge.svg)](https://github.com/brmorillo/utils/actions/workflows/ci.yml)
[![Downloads](https://img.shields.io/npm/dm/@brmorillo/utils.svg)](https://www.npmjs.com/package/@brmorillo/utils)
[![Bundle size](https://img.shields.io/bundlephobia/minzip/@brmorillo/utils?label=minzipped)](https://bundlephobia.com/package/@brmorillo/utils)
[![Node.js](https://img.shields.io/node/v/@brmorillo/utils?color=339933)](https://nodejs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178c6.svg)](https://www.typescriptlang.org/)
[![License: LGPL-3.0](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)

> If you have a problem, it's probably already solved here.

Expand Down Expand Up @@ -179,6 +182,8 @@ guarantees, see the [Security Policy](./SECURITY.md).
- 📚 **[Module reference](./docs/README.md)** — one page per module
- 🧪 **[Examples](./examples)** — runnable usage examples
- 🤖 **[CLAUDE.md](./CLAUDE.md)** — architecture & conventions for contributors and AI assistants
- 🤝 **[CONTRIBUTING.md](./CONTRIBUTING.md)** — how to contribute
- 🔒 **[SECURITY.md](./SECURITY.md)** — vulnerability reporting & security policy

## Development

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@brmorillo/utils",
"version": "14.1.0",
"version": "14.1.1",
"description": "Production-ready utility library for JS/TS — 27 modules behind one type-safe API: arrays, objects, strings, crypto, JWT, UUID, sorting, queues, caches, HTTP, logging, storage and more.",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down