Contributing
Getting started
Section titled “Getting started”git clone https://github.com/pedrotroccoli/1o1-utils.gitcd 1o1-utilspnpm installAvailable scripts
Section titled “Available scripts”| Command | Description |
|---|---|
pnpm test | Run tests |
pnpm test:coverage | Run tests with coverage report |
pnpm build | Compile TypeScript |
pnpm check | Lint + format check (Biome) |
pnpm check:fix | Lint + format auto-fix |
pnpm bench | Run all benchmarks |
pnpm size | Check bundle sizes |
Adding a new utility
Section titled “Adding a new utility”1. Create the folder
Section titled “1. Create the folder”src/<category>/<util-name>/Categories: arrays, async, browser, comparisons, formatters, functions, numbers, objects, strings, validators. Use kebab-case for the folder name.
2. Create the files
Section titled “2. Create the files”Every utility has exactly 4 files:
types.ts — Type definitions
interface MyUtilParams { // named parameters}
type MyUtilResult = // return type
type MyUtil = (params: MyUtilParams) => MyUtilResult;
export type { MyUtil, MyUtilParams, MyUtilResult };index.ts — Implementation
import type { MyUtilParams, MyUtilResult } from "./types.js";
/** * Brief description of what this utility does. * * @keywords common term 1, common term 2, common term 3 * @see RFC/Standard reference if applicable (https://...) */function myUtil({ param1, param2 }: MyUtilParams): MyUtilResult { // validate inputs // implementation}
export { myUtil };index.spec.ts — Tests (Mocha + Chai)
import { expect } from "chai";import { describe, it } from "mocha";import { myUtil } from "./index.js";
describe("myUtil", () => { it("should do the expected thing", () => { const result = myUtil({ param1: "value" }); expect(result).to.deep.equal(/* expected */); });});index.bench.ts — Benchmarks (tinybench)
import { Bench } from "tinybench";import { getDatasets } from "../../benchmarks/helpers.js";import { myUtil } from "./index.js";
const bench = new Bench({ name: "myUtil", time: 1000 });
for (const { name, data: getData } of getDatasets()) { const data = getData(); bench .add(`1o1-utils (${name})`, () => { myUtil({ /* ... */ }); }) .add(`lodash (${name})`, () => { /* lodash equivalent */ });}
export { bench };3. Register the utility
Section titled “3. Register the utility”Add the export to src/index.ts:
export { myUtil } from "./<category>/my-util/index.js";Add the export entry to package.json:
"./my-util": { "import": "./dist/<category>/my-util/index.js", "types": "./dist/<category>/my-util/index.d.ts"}Add a size-limit entry to .size-limit.json:
{ "name": "my-util", "path": "dist/<category>/my-util/index.js", "limit": "1 kB"}4. Update llms.txt and llms-full.txt
Section titled “4. Update llms.txt and llms-full.txt”Add the new utility to both files at the root of the repository:
llms.txt— add a link entry under the appropriate category sectionllms-full.txt— add a full documentation block with signature, parameters, return type, example, and edge cases
These files are served on the docs site for AI tool discoverability.
5. Add a playground example
Section titled “5. Add a playground example”The docs site ships an interactive playground (/playground/) plus a per-utility ## Try it block embedded on every utility page. Both are powered by the same Sandpack-based React component. Adding a new utility means contributing one example.
5a. Register the example
Section titled “5a. Register the example”Edit website/src/content/examples/index.ts and append an Example entry to the EXAMPLES array:
{ id: "my-util", // kebab-case, must match the doc page slug label: "myUtil", // shown in the playground selector category: "Arrays", // Arrays | Objects | Numbers | Strings | Async | Validators | Comparisons | Functions code: `import { myUtil } from "1o1-utils/my-util";
const result = myUtil({ /* params */ });
console.log(result);`,},Snippet guidelines:
- Use the published API (object-param form), not internals.
- Keep it under ~15 lines so it fits the editor without scrolling.
- Print output via
console.log— the playground console panel renders it. - Import from the per-utility subpath (
1o1-utils/my-util) to showcase tree-shaking. - Top-level
awaitis supported (Sandpackvanilla-tstemplate).
5b. Embed the playground in the doc page
Section titled “5b. Embed the playground in the doc page”Add the import + a ## Try it section right after the frontmatter and the one-line summary in website/src/content/docs/<category>/<my-util>.mdx:
---title: myUtildescription: Brief description---
import Playground from "../../../components/Playground.tsx";
Brief one-paragraph summary.
## Try it
<Playground client:only="react" utilityId="my-util" />
## Import...utilityId must match the id in EXAMPLES. The ../../../components/Playground.tsx path is correct for any docs/<category>/<file>.mdx page.
5c. Verify locally
Section titled “5c. Verify locally”pnpm docs:devOpen http://localhost:4321/1o1-utils/<category>/<my-util>/ and confirm the playground:
- Loads (Sandpack fetches
1o1-utilsfrom the CDN — first load takes a few seconds). - Runs the snippet without throwing.
- Prints the expected output to the console panel.
Also check /playground/ — your example should appear in the selector under its category.
6. Create a changeset
Section titled “6. Create a changeset”pnpm changesetChoose minor for new utilities, patch for bug fixes.
Code conventions
Section titled “Code conventions”- Named object parameters — all functions take a single object, never positional args. Exception: function composition utilities (
pipe,once) may use positional/variadic args when it’s the idiomatic pattern. - Type naming —
<Name>Params,<Name>Result,<Name>(function type) - No external dependencies — use only TypeScript/JS builtins
- Import extensions — always use
.jsin import paths (required for ESM) - Input validation — validate parameters and throw descriptive errors. Exception: checker functions (
isNil,isCircular,isEmpty) returnfalseinstead of throwing;safelyreturns a[error, result]tuple;getreturnsundefinedor a default value. - Named exports only — no default exports
- Immutability — all array/object utils must return new instances, never mutate inputs
Naming conventions
Section titled “Naming conventions”| Pattern | Convention | Example |
|---|---|---|
| Boolean checks | isX | isNil, isEmpty, isCircular |
| Validators | isValidX | isValidUrl, isValidEmail |
| Conversions | toX | toNumber |
| Formatters | formatX | formatSeconds |
| Generators | generateX | generateString |
| Normalizers | normalizeX | normalizeEmail |
| No type suffix | Don’t add the type to the name | clamp not clampNumber |
Discoverability (mandatory)
Section titled “Discoverability (mandatory)”Every utility must include:
-
@keywordsin JSDoc — common-language terms developers might search for:/*** Clamps a number between a minimum and maximum bound.** @keywords limit number, restrict range, min max, bound*/ -
@seein JSDoc — RFC or standard reference, if the util aligns with one:/*** @see RFC 5321 — SMTP (https://datatracker.ietf.org/doc/html/rfc5321)*/ -
“Also known as” on the docs page — alternative names for the same concept:
Also known as: limit number, restrict range, min/max bound
-
“Prompt suggestion” on the docs page — a ready-to-copy prompt for AI assistants. Use a fenced
textcode block (renders a copy button) and always prefix with the canonical references so the LLM can look up the real API:## Prompt suggestion```textI'm using 1o1-utils (npm: https://www.npmjs.com/package/1o1-utils, GitHub: https://github.com/pedrotroccoli/1o1-utils, LLM context: https://pedrotroccoli.github.io/1o1-utils/llms.txt). Show me how to use clamp to restrict a slider value between min and max```
Style (enforced by Biome)
Section titled “Style (enforced by Biome)”- 2-space indentation
- Double quotes
- Semicolons always
- Trailing commas
Run pnpm check:fix before committing.
Testing
Section titled “Testing”- Framework: Mocha + Chai
- Coverage: c8 with 80% minimum on lines, branches, functions, and statements
- Cover happy paths, edge cases, and error cases
Bundle size
Section titled “Bundle size”Each utility must stay under its size limit (1-2 kB brotli). The total library limit is 12 kB. Run pnpm size to verify.
Pull request checklist
Section titled “Pull request checklist”- All 4 files created (
index.ts,types.ts,index.spec.ts,index.bench.ts) - Export added to
src/index.ts - Export entry added to
package.json - Size-limit entry added to
.size-limit.json - Utility added to
llms.txtandllms-full.txt - Playground example added to
website/src/content/examples/index.ts -
## Try itblock with<Playground utilityId="..." />embedded in the docs page - Playground verified locally via
pnpm docs:dev -
@keywordsadded to JSDoc -
@seeRFC/standard reference added (if applicable) - “Also known as” section added to docs page
- “Prompt suggestion” section added to docs page
-
pnpm checkpasses -
pnpm testpasses with >80% coverage -
pnpm build && pnpm sizepasses - Changeset created