Skip to content

Contributing

Terminal window
git clone https://github.com/pedrotroccoli/1o1-utils.git
cd 1o1-utils
pnpm install
CommandDescription
pnpm testRun tests
pnpm test:coverageRun tests with coverage report
pnpm buildCompile TypeScript
pnpm checkLint + format check (Biome)
pnpm check:fixLint + format auto-fix
pnpm benchRun all benchmarks
pnpm sizeCheck bundle sizes
src/<category>/<util-name>/

Categories: arrays, async, browser, comparisons, formatters, functions, numbers, objects, strings, validators. Use kebab-case for the folder name.

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 };

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"
}

Add the new utility to both files at the root of the repository:

  • llms.txt — add a link entry under the appropriate category section
  • llms-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.

Terminal window
pnpm changeset

Choose minor for new utilities, patch for bug fixes.

  • 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 .js in import paths (required for ESM)
  • Input validation — validate parameters and throw descriptive errors. Exception: checker functions (isNil, isCircular, isEmpty) return false instead of throwing; safely returns a [error, result] tuple; get returns undefined or a default value.
  • Named exports only — no default exports
  • Immutability — all array/object utils must return new instances, never mutate inputs
PatternConventionExample
Boolean checksisXisNil, isEmpty, isCircular
ValidatorsisValidXisValidUrl, isValidEmail
ConversionstoXtoNumber
FormattersformatXformatSeconds
GeneratorsgenerateXgenerateString
NormalizersnormalizeXnormalizeEmail
No type suffixDon’t add the type to the nameclamp not clampNumber

Every utility must include:

  1. @keywords in 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
    */
  2. @see in JSDoc — RFC or standard reference, if the util aligns with one:

    /**
    * @see RFC 5321 — SMTP (https://datatracker.ietf.org/doc/html/rfc5321)
    */
  3. “Also known as” on the docs page — alternative names for the same concept:

    Also known as: limit number, restrict range, min/max bound

  4. “Prompt suggestion” on the docs page — a ready-to-copy prompt for AI assistants. Use a fenced text code block (renders a copy button) and always prefix with the canonical references so the LLM can look up the real API:

    ## Prompt suggestion
    ```text
    I'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
    ```
  • 2-space indentation
  • Double quotes
  • Semicolons always
  • Trailing commas

Run pnpm check:fix before committing.

  • Framework: Mocha + Chai
  • Coverage: c8 with 80% minimum on lines, branches, functions, and statements
  • Cover happy paths, edge cases, and error cases

Each utility must stay under its size limit (1-2 kB gzipped). The total library limit is 5 kB gzipped. Run pnpm size to verify.

  • 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.txt and llms-full.txt
  • @keywords added to JSDoc
  • @see RFC/standard reference added (if applicable)
  • “Also known as” section added to docs page
  • “Prompt suggestion” section added to docs page
  • pnpm check passes
  • pnpm test passes with >80% coverage
  • pnpm build && pnpm size passes
  • Changeset created