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
67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CI

on:
push:
branches: ['main']
tags: ['v*']
pull_request:
branches: ['*']

workflow_dispatch:

concurrency:
group: ${{ github.ref }}
cancel-in-progress: true

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 10
run_install: false

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: pnpm install

- run: pnpm validate

- uses: SonarSource/sonarqube-scan-action@v7.0.0
if: "!startsWith(github.ref, 'refs/tags/')"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Comment thread
gilbarbara marked this conversation as resolved.

publish:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs: validate
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
with:
version: 10
run_install: false

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
registry-url: https://registry.npmjs.org

- run: npm install -g npm@11

- run: pnpm install

- run: npm publish --provenance
76 changes: 0 additions & 76 deletions .github/workflows/main.yml

This file was deleted.

46 changes: 46 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
pnpm build # Clean and build with tsup (outputs dist/)
pnpm lint # ESLint with auto-fix
pnpm typecheck # TypeScript check (noEmit)
pnpm test # Runs vitest once
pnpm test:watch # Runs vitest watch mode
pnpm test:coverage # Runs tests with coverage
pnpm validate # Full validation: lint + typecheck + test:coverage + build + size
```

Run a single test file:
```bash
pnpm test test/arrays.spec.ts
```

Run tests matching a pattern:
```bash
pnpm test -t "should return true"
```

## Architecture

Single-purpose library exporting one default function `equal(left, right)` that performs deep equality comparison.

**Source structure:**
- `src/index.ts` - Main `equal` function with specialized comparators for arrays, Maps, Sets, ArrayBuffers, and objects
- `src/helpers.ts` - Type guard utilities (`isObject`, `isRegex`, etc.)
- `src/types.ts` - TypeScript type definitions

**Key implementation details:**
- Circular references: Handled via WeakMap/WeakSet tracking to prevent infinite recursion in self-referential or cross-referential structures
- React elements: Skips `_owner` property (contains circular refs) when `$$typeof` is present
- NaN handling: `NaN === NaN` returns true
- Comparison order: Reference equality → constructor match → type-specific comparison → valueOf/toString fallback → key-by-key recursion

**Tests** are organized by data type in `test/*.spec.ts` (scalars, objects, arrays, dates, regex, functions, bigint, maps, sets, typed-arrays).

## Build

Uses `tsup` with dual output (CJS + ESM). Size limit: 1kB per format.
15 changes: 15 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import config from '@gilbarbara/eslint-config';
import testingLibrary from '@gilbarbara/eslint-config/testing-library';
import vitest from '@gilbarbara/eslint-config/vitest';

export default [
...config,
...vitest,
...testingLibrary,
{
files: ['**/?(*.)+(spec|test).[jt]s?(x)'],
rules: {
'no-console': 'off',
},
},
];
63 changes: 29 additions & 34 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,43 +32,43 @@
"typescript"
],
"devDependencies": {
"@gilbarbara/eslint-config": "^0.5.4",
"@gilbarbara/eslint-config": "^1.0.4",
"@gilbarbara/prettier-config": "^1.0.0",
"@gilbarbara/tsconfig": "^0.2.3",
"@size-limit/preset-small-lib": "^9.0.0",
"@types/node": "^20.8.4",
"@types/react": "^18.2.28",
"@types/react-dom": "^18.2.13",
"@types/react-test-renderer": "^18.0.3",
"@vitest/coverage-v8": "^0.34.6",
"del-cli": "^5.1.0",
"happy-dom": "^12.7.0",
"husky": "^8.0.3",
"is-ci-cli": "^2.2.0",
"jest-extended": "^4.0.2",
"react": "^18.2.0",
"react-test-renderer": "^18.2.0",
"repo-tools": "^0.2.2",
"size-limit": "^9.0.0",
"ts-node": "^10.9.1",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"vitest": "^0.34.6"
"@gilbarbara/tsconfig": "^1.0.0",
"@size-limit/preset-small-lib": "^12.0.0",
"@testing-library/react": "^16.3.2",
"@types/node": "^22.19.8",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitest/coverage-v8": "^4.0.18",
"del-cli": "^7.0.0",
"eslint": "^9.39.2",
"happy-dom": "^20.5.0",
"husky": "^9.1.7",
"jest-extended": "^7.0.0",
"prettier": "^3.8.1",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"repo-tools": "^0.3.1",
"size-limit": "^12.0.0",
"ts-node": "^10.9.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
"vitest": "^4.0.18"
},
"scripts": {
"build": "npm run clean && tsup",
"build": "pnpm clean && tsup",
"watch": "tsup --watch",
"clean": "del dist/*",
"test": "is-ci \"test:coverage\" \"test:watch\"",
"test:coverage": "TZ=UTC vitest run --coverage",
"test:watch": "TZ=UTC vitest watch",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest watch",
"lint": "eslint --fix src test",
"typecheck": "tsc",
"typecheck": "tsc --p test/tsconfig.json",
"format": "prettier \"**/*.{css,graphql,js,json,jsx,less,md,mdx,scss,ts,tsx,yaml,yml}\" --write",
"validate": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run size",
"validate": "pnpm lint && pnpm typecheck && pnpm test:coverage && pnpm build && pnpm size",
"size": "size-limit",
"prepublishOnly": "npm run validate",
"prepare": "husky install"
"prepare": "husky"
},
"tsup": {
"cjsInterop": true,
Expand All @@ -83,11 +83,6 @@
"sourcemap": true,
"splitting": false
},
"eslintConfig": {
"extends": [
"@gilbarbara/eslint-config"
]
},
"prettier": "@gilbarbara/prettier-config",
"size-limit": [
{
Expand Down
Loading