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.

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.

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 await is supported (Sandpack vanilla-ts template).

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: myUtil
description: 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.

Terminal window
pnpm docs:dev

Open http://localhost:4321/1o1-utils/<category>/<my-util>/ and confirm the playground:

  1. Loads (Sandpack fetches 1o1-utils from the CDN — first load takes a few seconds).
  2. Runs the snippet without throwing.
  3. Prints the expected output to the console panel.

Also check /playground/ — your example should appear in the selector under its category.

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 brotli). The total library limit is 12 kB. 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
  • Playground example added to website/src/content/examples/index.ts
  • ## Try it block with <Playground utilityId="..." /> embedded in the docs page
  • Playground verified locally via pnpm docs:dev
  • @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