Skip to content

Feat: Add initial Node FormRequest package#1

Merged
soulevilx merged 3 commits into
developfrom
feature/initial-node-formrequest-package
May 13, 2026
Merged

Feat: Add initial Node FormRequest package#1
soulevilx merged 3 commits into
developfrom
feature/initial-node-formrequest-package

Conversation

@soulevilx
Copy link
Copy Markdown
Contributor

@soulevilx soulevilx commented May 13, 2026

Summary

  • Add initial TypeScript FormRequest package with framework-neutral validation
  • Add optional Express-style adapter, tests, docs, CI, and AI contributor guidance
  • Add AI/human ignore files and package metadata

Validation

  • npm run lint
  • npm run typecheck
  • npm run test:coverage
  • npm run build
  • npm pack --dry-run

Coverage: 100% statements, branches, functions, and lines.

Summary by CodeRabbit

  • New Features

    • Introduced a TypeScript-based validation framework with FormRequest utility supporting authorization checks and grouped error reporting.
    • Added 18 reusable validation rules (required, string, email, url, min, max, between, etc.).
    • Included optional Express-like request adapter for seamless integration.
    • Enabled custom validation messages and field attribute mapping.
  • Documentation

    • Added comprehensive README with usage examples and public API documentation.
    • Included release process, CI/CD, and contributor guidance.
  • Chores

    • Configured ESLint, TypeScript, and Vitest with 100% coverage enforcement.
    • Set up GitHub Actions CI pipeline.
    • Added MIT License and project metadata.

Review Change Stack

@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Warning

Rate limit exceeded

@soulevilx has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 29 minutes and 55 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: acec8705-ad54-437a-bf8c-9ba4000930b6

📥 Commits

Reviewing files that changed from the base of the PR and between 7644cf0 and 40e9c3a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (23)
  • .github/skills/formrequest-package/SKILL.md
  • AGENTS.md
  • CHANGELOG.md
  • CLAUDE.md
  • README.md
  • ai/skills/README.md
  • ai/skills/USAGE.md
  • docs/README.md
  • docs/ai-skills.md
  • docs/ci-cd.md
  • docs/release-process.md
  • eslint.config.js
  • package.json
  • src/FormRequest.ts
  • src/adapters/express.ts
  • src/exceptions/AuthorizationException.ts
  • src/exceptions/FormRequestException.ts
  • src/exceptions/ValidationException.ts
  • src/exceptions/index.ts
  • src/index.ts
  • src/types.ts
  • tests/formrequest.test.ts
  • tsconfig.json
📝 Walkthrough

Walkthrough

This PR introduces @jooservices/formrequest, a TypeScript form validation library with framework-neutral architecture. It defines validation type contracts, implements rule factories for common validation scenarios, provides a FormRequest class supporting Express-like requests and optional async authorization, includes comprehensive test coverage at 100%, and establishes CI/CD automation, project configuration, and contributor documentation.

Changes

FormRequest Validation Library

Layer / File(s) Summary
Validation type contracts
src/types.ts
InputBag, RuleContext, ValidationMessage, ValidationIssue, ValidationResult<TData>, Rule, RuleSet, FormRequestConfig<TData>, and ExpressLikeRequest define the type system for rules, validation flow, and request configuration.
Rule system and factories
src/rules/createRule.ts, src/rules/index.ts
isEmpty predicate, createRule factory, and rule functions (required, optional, nullable, string, number, boolean, array, object, email, url, min, max, between, length, regex, accepted, inValues) with message templating and :attribute substitution.
FormRequest class and package entry
src/FormRequest.ts, src/index.ts
AuthorizationError, ValidationError<TData>, and FormRequest<TData> class with validate(), validateOrThrow(), validated(), errors() APIs and fromExpress() static helper; main package export surface re-exporting all rules and types.
Validation test suite
tests/formrequest.test.ts
11 test cases covering successful validation with field whitelisting, grouped error reporting with custom messages and attribute mapping, authorization/validation failures, Express input merging with body precedence, malformed source resilience, edge cases, URL validation, and rule message defaults.
Build and tooling configuration
package.json, tsconfig.json, eslint.config.js, vitest.config.ts
ES module package with build, lint, typecheck, test, test:coverage scripts; TypeScript strict mode with declaration emission; ESLint flat config with typescript-eslint strict type-checking; Vitest with V8 coverage enforcement (100% thresholds).
Repository setup and CI/CD automation
.gitignore, .aiignore, .humanignore, .github/workflows/ci.yml, .github/pull_request_template.md, .github/skills/formrequest-package/SKILL.md, LICENSE
Version control ignore patterns, GitHub Actions CI pipeline running lint→typecheck→coverage→build→pack on PR/push to develop/master, pull request template with validation and review checklists, SKILL.md defining ownership and guardrails, and MIT 2026 license.
Project documentation and guidance
README.md, CHANGELOG.md, AGENTS.md, CLAUDE.md, docs/*, ai/skills/*
Package overview, install instructions, quick-start validation example, public API listing, initial changelog entry, repository agent instructions, contributor guidelines, documentation hub linking release process/CI/CD/AI skills, and AI skills usage guidance.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A FormRequest is born today,
With rules and types aligned the way,
Express-like inputs validate with grace,
And errors grouped in their own place.
TypeScript strict and tests complete,
A brand new package, oh so neat! 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the primary change: introducing an initial FormRequest package for Node.js with TypeScript support, which is the main objective of this comprehensive changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/initial-node-formrequest-package

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
tests/formrequest.test.ts (1)

123-135: ⚡ Quick win

Avoid order-coupled assertion for issues rules.

This assertion is brittle against harmless internal ordering changes. Prefer membership + count assertions unless rule order is part of the public contract.

♻️ Suggested test hardening
-    expect(result.issues.map((issue) => issue.rule)).toEqual([
+    expect(result.issues.map((issue) => issue.rule)).toEqual(expect.arrayContaining([
       'required',
       'email',
       'number',
       'url',
       'accepted',
       'array',
       'object',
       'length',
       'regex',
       'in',
       'between'
-    ]);
+    ]));
+    expect(result.issues).toHaveLength(11);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/formrequest.test.ts` around lines 123 - 135, The test currently asserts
exact ordering of result.issues.map(issue => issue.rule), which is brittle;
change it to assert membership and count instead: replace the strict order
assertion with an assertion that the array contains all expected rule names (use
an "arrayContaining"/membership-style assertion against the list
['required','email','number','url','accepted','array','object','length','regex','in','between'])
and add a separate assertion that result.issues.length (or the mapped rules
length) equals 11 so the test verifies presence and count but not order; locate
the assertion in tests/formrequest.test.ts that references
result.issues.map((issue) => issue.rule) and update it accordingly.
src/rules/index.ts (1)

89-99: ⚡ Quick win

Consider the POSITIVE_INFINITY fallback behavior for non-measurable types.

The measurableLength helper returns Number.POSITIVE_INFINITY for types that don't have a measurable length (objects, dates, etc.). This means:

  • min(10) will pass for objects/dates (∞ >= 10)
  • max(10) will fail for objects/dates (∞ > 10)
  • between(5, 10) will fail for objects/dates (∞ > 10)
  • length(10) will fail for objects/dates (∞ ≠ 10)

While this behavior might be intentional, the asymmetry could be counterintuitive—min constraints pass for non-measurable values while max/between/length fail. Consider whether returning 0 or explicitly failing validation would be clearer.

If this design is intentional, document it so users understand that length constraints are meant for numbers, strings, and arrays only.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/rules/index.ts` around lines 89 - 99, The measurableLength helper
currently returns Number.POSITIVE_INFINITY for non-measurable types causing
asymmetric validation; change measurableLength to return NaN for any type that
isn't number, string, or array, then update the validators that call
measurableLength (e.g., the min, max, between, length validation functions) to
treat NaN as an explicit non-measurable value and fail validation (or return a
clear "non-measurable" error) instead of comparing against Infinity; also add a
short comment/docstring near measurableLength explaining that non-measurable
types produce NaN and are considered validation failures for length-based rules.
package.json (1)

3-3: ⚡ Quick win

Update version before publishing to npm.

Version 0.0.0 is a pre-release placeholder. Consider updating to 0.1.0 or 1.0.0 before the first npm publish.

Would you like me to open an issue to track the version update task?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 3, Update the "version" field in package.json from the
placeholder "0.0.0" to an appropriate release version (e.g., "0.1.0" or "1.0.0")
before publishing to npm; locate the "version" key in package.json and bump it
accordingly, and optionally create or link an issue to track future versioning
and release notes.
tsconfig.json (1)

9-18: 💤 Low value

Consider aligning with standard library TypeScript project structure.

The current setup uses rootDir: "." and includes config files (vitest.config.ts, eslint.config.js) in the TypeScript project. While this works because tsup handles compilation independently, it's non-standard for libraries:

  • Standard pattern: rootDir: "src", include: ["src"] keeps the TypeScript project focused on application code
  • Current pattern: Including the entire project makes it unclear what's part of the distributable library

Since tsc is only used for type-checking (--noEmit), this doesn't affect the build output, but it may confuse contributors expecting typical library structure.

♻️ Suggested standard structure
 {
   "compilerOptions": {
     "declaration": true,
     "exactOptionalPropertyTypes": true,
     "module": "NodeNext",
     "moduleResolution": "NodeNext",
     "noUncheckedIndexedAccess": true,
     "outDir": "dist",
-    "rootDir": ".",
+    "rootDir": "src",
     "strict": true,
     "target": "ES2022"
   },
   "include": [
-    "src",
-    "tests",
-    "vitest.config.ts",
-    "eslint.config.js"
+    "src"
   ]
 }

Note: Tests and config files would still be type-checked if they import from src, but wouldn't be part of the primary project compilation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tsconfig.json` around lines 9 - 18, Update tsconfig.json to use a standard
library layout by setting "rootDir" to "src" and restricting the "include" array
to only "src" (remove entries like "tests", "vitest.config.ts",
"eslint.config.js"); this keeps type checking focused on source files and avoids
treating test/config files as part of the primary project compilation while
still allowing them to import from src for type-checking.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 47-54: The peer dependency for Express is too broad and may allow
incompatible Express 5.x; update package.json's "peerDependencies" entry for
"express" to ">=4.18 <5" to exclude v5, or alternatively add explicit
compatibility tests that exercise your ExpressLikeRequest types against both
Express 4.x and 5.x (covering req.body, req.query, req.params, and removal of
req.param) and only keep the current range if those tests pass; ensure
references to the ExpressLikeRequest type reflect any behavior differences
discovered.

---

Nitpick comments:
In `@package.json`:
- Line 3: Update the "version" field in package.json from the placeholder
"0.0.0" to an appropriate release version (e.g., "0.1.0" or "1.0.0") before
publishing to npm; locate the "version" key in package.json and bump it
accordingly, and optionally create or link an issue to track future versioning
and release notes.

In `@src/rules/index.ts`:
- Around line 89-99: The measurableLength helper currently returns
Number.POSITIVE_INFINITY for non-measurable types causing asymmetric validation;
change measurableLength to return NaN for any type that isn't number, string, or
array, then update the validators that call measurableLength (e.g., the min,
max, between, length validation functions) to treat NaN as an explicit
non-measurable value and fail validation (or return a clear "non-measurable"
error) instead of comparing against Infinity; also add a short comment/docstring
near measurableLength explaining that non-measurable types produce NaN and are
considered validation failures for length-based rules.

In `@tests/formrequest.test.ts`:
- Around line 123-135: The test currently asserts exact ordering of
result.issues.map(issue => issue.rule), which is brittle; change it to assert
membership and count instead: replace the strict order assertion with an
assertion that the array contains all expected rule names (use an
"arrayContaining"/membership-style assertion against the list
['required','email','number','url','accepted','array','object','length','regex','in','between'])
and add a separate assertion that result.issues.length (or the mapped rules
length) equals 11 so the test verifies presence and count but not order; locate
the assertion in tests/formrequest.test.ts that references
result.issues.map((issue) => issue.rule) and update it accordingly.

In `@tsconfig.json`:
- Around line 9-18: Update tsconfig.json to use a standard library layout by
setting "rootDir" to "src" and restricting the "include" array to only "src"
(remove entries like "tests", "vitest.config.ts", "eslint.config.js"); this
keeps type checking focused on source files and avoids treating test/config
files as part of the primary project compilation while still allowing them to
import from src for type-checking.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e2812118-363a-4a9d-9f3d-04ece6a49e49

📥 Commits

Reviewing files that changed from the base of the PR and between 9f79d0d and 7644cf0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (27)
  • .aiignore
  • .github/pull_request_template.md
  • .github/skills/formrequest-package/SKILL.md
  • .github/workflows/ci.yml
  • .gitignore
  • .humanignore
  • AGENTS.md
  • CHANGELOG.md
  • CLAUDE.md
  • LICENSE
  • README.md
  • ai/skills/README.md
  • ai/skills/USAGE.md
  • docs/README.md
  • docs/ai-skills.md
  • docs/ci-cd.md
  • docs/release-process.md
  • eslint.config.js
  • package.json
  • src/FormRequest.ts
  • src/index.ts
  • src/rules/createRule.ts
  • src/rules/index.ts
  • src/types.ts
  • tests/formrequest.test.ts
  • tsconfig.json
  • vitest.config.ts

Comment thread package.json
@soulevilx soulevilx merged commit 195174d into develop May 13, 2026
3 checks passed
@soulevilx soulevilx deleted the feature/initial-node-formrequest-package branch May 13, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant