-
Notifications
You must be signed in to change notification settings - Fork 0
V2.1.0 rc #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
V2.1.0 rc #1
Changes from 49 commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
229bf22
feat: initial release of @git-stunts/trailer-codec
flyingrobots d243810
feat(git-stunts): architect the 900 stunt. sharded roaring bitmaps, s…
flyingrobots fbec60a
feat: harden trailer-codec for npm publication
flyingrobots 35627c1
docs: add fresh post-hardening audit
flyingrobots d56dd63
docs: capture best material for Git Stunts blog series
flyingrobots 2cafd87
fix(trailer-codec): guard docker tests and reuse key pattern
flyingrobots 46abef2
chore(trailer-codec): drop guard and unused dependency
flyingrobots 0c4db96
chore(trailer-codec): remove benchmarks
flyingrobots 77723f4
feat(trailer-codec): polish helpers and docs
flyingrobots 40d364d
refactor(trailer-codec): expose parser strategy and clean facade
flyingrobots ef46834
docs: expand README and add reference guides
flyingrobots ba88a51
docs: normalize changelog bullet spacing
flyingrobots 6aa60ac
docs: clarify encodeMessage factory
flyingrobots 40d5349
docs: clarify codec helpers
flyingrobots c4c4765
docs: format git commit message signature
flyingrobots e2591ec
docs: note schema bundle defaults
flyingrobots 30a65cf
docs: clarify encode payload validation
flyingrobots 990c830
docs: add validation error origins
flyingrobots 0ed237d
docs: clarify usage structure
flyingrobots 089631b
docs: add breaking change guidance
flyingrobots a1fd4a5
docs: refine configured codec example
flyingrobots 98979d2
docs: restructure helper descriptions
flyingrobots d701779
chore: Remove wack files
flyingrobots 14d24bb
docs: clarify security scope
flyingrobots c7837a1
docs: detail vitest debug flags
flyingrobots 50377f7
docs: clarify snapshot policy
flyingrobots f4b0c07
docs: describe integration API contract
flyingrobots 7a64126
docs: clarify parser regex
flyingrobots 3c1ef40
fix: harden trailer normalization
flyingrobots 5a272b1
refactor: remove shared codec service
flyingrobots b8a4e23
fix: validate normalized input
flyingrobots c1900ab
docs: make TrailerCodec primary
flyingrobots 88b8ab5
refactor: clarify TrailerCodec API
flyingrobots 7f1c3ed
chore: clarify trailer key exports
flyingrobots da2807e
chore: rename trailer key pattern export
flyingrobots 75d03eb
test: ensure service not called on invalid input
flyingrobots ffaa74d
test: assert service stays untouched
flyingrobots 8f99482
test: guard invalid message objects
flyingrobots 33c690c
test: assert body format helper calls
flyingrobots 000835d
test: assert trailer newline code
flyingrobots aedcfc7
test: verify docs metadata
flyingrobots 925cebf
test: drop private composeBody assertion
flyingrobots e3af0a7
test: drop private prepareLines assertion
flyingrobots 380511c
refactor: reuse formatter helper
flyingrobots 5ebfb26
feat: validate commit formatter inputs
flyingrobots 1826f84
fix: sanitize key pattern regex
flyingrobots e0360da
fix: harden trailer schema
flyingrobots 7a2465d
chore: remove jsdoctor scripts
flyingrobots e8bcc0f
chore(release): v2.1.0 - production readiness overhaul and architectu…
flyingrobots b129437
Update docs/ADVANCED.md
flyingrobots 12911f5
Update docs/MIGRATION.md
flyingrobots 150993e
Update docs/SERVICE.md
flyingrobots 22b636e
Update scripts/pre-commit.sh
flyingrobots 202712e
Update docs/SERVICE.md
flyingrobots 0c8e02b
chore: Fixes from PR code review
flyingrobots 68a4dd2
Merge branch 'v2.1.0-rc' of github.com:git-stunts/trailer-codec into …
flyingrobots File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ main ] | ||
| pull_request: | ||
| branches: [ main ] | ||
|
|
||
| jobs: | ||
| lint: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Use Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
| cache: 'npm' | ||
| - run: npm install | ||
| - run: npm run lint | ||
|
|
||
| test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Use Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
| cache: 'npm' | ||
| - run: npm install | ||
| - run: npm test |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| # Dependency directories | ||
| node_modules/ | ||
| jspm_packages/ | ||
| bun.lockb | ||
| node_modules.bun/ | ||
|
|
||
| # Deno | ||
| .deno/ | ||
| deno.lock | ||
|
|
||
| # Build outputs | ||
| dist/ | ||
| build/ | ||
| .next/ | ||
| .nuxt/ | ||
| .output/ | ||
| .cache/ | ||
| out/ | ||
|
|
||
| # Logs | ||
| logs | ||
| *.log | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
| lerna-debug.log* | ||
| .pnpm-debug.log* | ||
|
|
||
| # Diagnostic reports (https://nodejs.org/api/report.html) | ||
| report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||
|
|
||
| # Runtime data | ||
| pids | ||
| *.pid | ||
| *.seed | ||
| *.pid.lock | ||
|
|
||
| # Directory for instrumented libs generated by jscoverage/JSCover | ||
| lib-cov | ||
|
|
||
| # Coverage directory used by tools like istanbul | ||
| coverage | ||
| *.lcov | ||
|
|
||
| # nyc documentation | ||
| .nyc_output | ||
|
|
||
| # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | ||
| .grunt | ||
|
|
||
| # Bower dependency directory (https://bower.io/) | ||
| bower_components | ||
|
|
||
| # node-waf configuration | ||
| .lock-wscript | ||
|
|
||
| # Compiled binary addons (https://nodejs.org/api/addons.html) | ||
| build/Release | ||
|
|
||
| # Dependency directories | ||
| jspm_packages/ | ||
|
|
||
| # TypeScript v1 declaration files | ||
| typings/ | ||
|
|
||
| # TypeScript cache | ||
| *.tsbuildinfo | ||
|
|
||
| # Optional npm cache directory | ||
| .npm | ||
|
|
||
| # Optional eslint cache | ||
| .eslintcache | ||
|
|
||
| # Optional stylelint cache | ||
| .stylelintcache | ||
|
|
||
| # Optional REPL history | ||
| .node_repl_history | ||
|
|
||
| # Output of 'npm pack' | ||
| *.tgz | ||
|
|
||
| # Yarn Integrity file | ||
| .yarn-integrity | ||
|
|
||
| # dotenv environment variable files | ||
| .env | ||
| .env.development.local | ||
| .env.test.local | ||
| .env.production.local | ||
| .env.local | ||
|
|
||
| # parcel-bundler cache (https://parceljs.org/) | ||
| .cache | ||
| .parcel-cache | ||
|
|
||
| # Next.js build output | ||
| .next | ||
| out | ||
|
|
||
| # Nuxt.js build / generate output | ||
| .nuxt | ||
| dist | ||
|
|
||
| # Gatsby files | ||
| .cache/ | ||
| public/ | ||
|
|
||
| # vue-cli dist | ||
| dist/ | ||
|
|
||
| # Serverless directories | ||
| .serverless/ | ||
|
|
||
| # FuseBox cache | ||
| .fusebox/ | ||
|
|
||
| # DynamoDB Local files | ||
| .dynamodb/ | ||
|
|
||
| # Tern JS port file | ||
| .tern-port | ||
|
|
||
| # Stores VS Code state | ||
| .vscode/* | ||
| !.vscode/settings.json | ||
| !.vscode/tasks.json | ||
| !.vscode/launch.json | ||
| !.vscode/extensions.json | ||
| !.vscode/code-actions.json | ||
|
|
||
| # IntelliJ IDEA | ||
| .idea/ | ||
|
|
||
| .crush | ||
| .obsidian | ||
|
|
||
| # macOS | ||
| .DS_Store | ||
| .AppleDouble | ||
| .LSOverride | ||
| Icon | ||
|
|
||
|
|
||
| # Thumbnails | ||
| ._* | ||
|
|
||
| # Files that might appear in the root of a volume | ||
| .DocumentRevisions-V100 | ||
| .fseventsd | ||
| .Spotlight-V100 | ||
| .TemporaryItems | ||
| .Trashes | ||
| .VolumeIcon.icns | ||
| .com.apple.timemachine.donotpresent | ||
|
|
||
| # Directories potentially created by macOS | ||
| .AppleDB | ||
| .AppleDesktop | ||
| Network Trash Folder | ||
| Temporary Items | ||
| .apdisk | ||
|
|
||
| # Other Editors | ||
| *.swp | ||
| *.swo | ||
| *~ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # API Reference | ||
|
|
||
| This file catalogs every public export from `@git-stunts/trailer-codec` so you can confidently import, configure, and extend the codec. | ||
|
|
||
| ## Encoding & decoding helpers | ||
|
|
||
| ### `decodeMessage(message: string)` | ||
| - Deprecated convenience wrapper around `new TrailerCodec().decode(message)`. | ||
| - Input: a raw commit payload (title, optional body, trailers) as a string. | ||
| - Output: `{ title: string, body: string, trailers: Record<string, string> }` where `body` is trimmed via `formatBodySegment` (see below) and trailer keys are normalized to lowercase. | ||
| - Throws `TrailerCodecError` subclasses (e.g., `TrailerNoSeparatorError`, `TrailerValueInvalidError`, or `CommitMessageInvalidError`) for invalid titles, missing blank lines, oversized messages, or malformed trailers. | ||
|
|
||
| ### `encodeMessage({ title: string, body?: string, trailers?: Record<string, string> })` | ||
| -- Deprecated convenience wrapper around `new TrailerCodec().encode(payload)`. | ||
| - Builds a `GitCommitMessage` under the hood and returns the canonical string. Trailers are converted from plain objects to `GitTrailer` instances via the default factory (see `GitTrailer` below). | ||
|
|
||
| ### `formatBodySegment(body?: string, { keepTrailingNewline = false })` | ||
| - Shared helper for `decodeMessage` to trim whitespace while optionally keeping a trailing newline when you plan to write the body back into a template. | ||
|
|
||
| ### `createMessageHelpers({ service, bodyFormatOptions } = {})` | ||
| - Returns `{ decodeMessage, encodeMessage }` bound to the injected `TrailerCodecService` instance; a new service is created when none is provided. | ||
| - Supports `bodyFormatOptions` (forwarded to `formatBodySegment`) and is useful for advanced/test wiring. | ||
|
|
||
| ### `createDefaultTrailerCodec({ bodyFormatOptions } = {})` | ||
| - Creates a new `TrailerCodecService`, builds a `TrailerCodec`, and returns it so you can call `encodeMessage()`/`decodeMessage()` without manually wiring services. | ||
|
|
||
| ### `TrailerCodec` | ||
| - Constructor opts: `{ service = new TrailerCodecService(), bodyFormatOptions }`. | ||
| - Exposes `decodeMessage(input)`/`decode(input)` and `encodeMessage(payload)`/`encode(payload)` methods that delegate to `createMessageHelpers()`. | ||
| - The `decode()` and `encode()` methods are convenience aliases added in v2.1.0. | ||
|
|
||
| ### `createConfiguredCodec({ keyPattern, keyMaxLength, parserOptions, formatters, bodyFormatOptions } = {})` | ||
| - Creates a schema bundle via `createGitTrailerSchemaBundle`, a `TrailerParser`, and a `TrailerCodecService`, then exposes `{ service, helpers, decodeMessage, encodeMessage }`. | ||
| - Use this when you need custom trailer patterns, parser tweaks, formatter hooks, or tightly controlled key lengths. | ||
|
|
||
| ## Domain model exports | ||
|
|
||
| ### `GitCommitMessage` | ||
| ```ts | ||
| new GitCommitMessage( | ||
| payload: { title: string; body?: string; trailers?: GitTrailerInput[] }, | ||
| options?: { trailerSchema?: ReturnType<typeof getDefaultTrailerSchemaBundle>['schema']; formatters?: { titleFormatter?: (value: string) => string; bodyFormatter?: (value: string) => string } } | ||
| ); | ||
| ``` | ||
| - Validates via `GitCommitMessageSchema`, normalizes title/body with optional formatters, and converts `trailers` to `GitTrailer` instances. | ||
| - `toString()` returns a Git-style commit string (title, optional body, blank line, trailers). | ||
|
|
||
| ### `GitTrailer` | ||
| - Accepts `(key: string, value: string, schema = GitTrailerSchema)`. | ||
| - Validates using `GitTrailerSchema` and normalizes the key to lowercase and the value to a trimmed string. | ||
| - Throws `TrailerInvalidError` or `TrailerValueInvalidError` when the provided key/value fail schema validation. | ||
|
|
||
| ## Services & parsers | ||
|
|
||
| ### `TrailerCodecService` | ||
| - Core decode/encode logic; see `docs/SERVICE.md` for how the pipeline is wired. | ||
| - Constructor options: | ||
| - `schemaBundle`: result of `createGitTrailerSchemaBundle({ keyPattern, keyMaxLength })` (defaults: `keyPattern` = `[A-Za-z0-9_-]+`, `keyMaxLength` = `100`, see the schema section below). | ||
| - `trailerFactory`: function that instantiates trailers (defaults to `GitTrailer`). | ||
| - `parser`: instance of `TrailerParser`. | ||
| - `messageNormalizer`, `titleExtractor`, `bodyComposer`: helper classes that normalize lines, extract the title, and compose the body. | ||
| - `formatters`: optional `{ titleFormatter, bodyFormatter }` that run before serialization. | ||
| - `decode(message)` enforces message size, normalizes lines, extracts the title, splits body/trailers with `TrailerParser`, composes the body, builds trailers with `trailerFactory`, and constructs a `GitCommitMessage`. | ||
| - `encode(messageEntity)` accepts either a `GitCommitMessage` instance or a plain payload object, validates it against `GitCommitMessageSchema`, and returns the canonical commit string produced by the entity. | ||
|
|
||
| ### `TrailerParser` | ||
| - Constructor takes `{ keyPattern = TRAILER_KEY_RAW_PATTERN_STRING }`. | ||
| - `split(lines)` finds where the trailer block begins (walks backward, validates the blank-line separator) and returns `{ bodyLines, trailerLines }`. | ||
| - Used internally by `TrailerCodecService` and is injectable for custom parsing strategies. | ||
|
|
||
| ## Schemas & constants | ||
|
|
||
| ### `createGitTrailerSchemaBundle({ keyPattern, keyMaxLength } = {})` | ||
| - Returns `{ schema, keyPattern, keyRegex }` with the schema used by `GitTrailer` and `GitCommitMessage`. | ||
| - Default `keyPattern` is `[A-Za-z0-9_-]+` and `keyMaxLength` defaults to `100`. | ||
|
|
||
| ### `TRAILER_KEY_RAW_PATTERN_STRING` / `TRAILER_KEY_REGEX` | ||
| - Exported from the default schema bundle; use them to keep custom parsers aligned with validation rules. | ||
|
|
||
| ## Errors | ||
|
|
||
| ### `TrailerCodecError` | ||
| - Base error type used throughout the codec (`index.js` re-exports it). | ||
| - Signature: `(message: string, meta: Record<string, unknown> = {})`. | ||
|
|
||
| ### Validation error subclasses | ||
|
|
||
| | Error | Thrown by | Meaning | | ||
| | --- | --- | --- | | ||
| | `TrailerTooLargeError` | `MessageNormalizer.guardMessageSize` (called by `TrailerCodecService.decode` and the exported `decodeMessage`) | Message exceeds the 5 MB guard in `MessageNormalizer`. | | ||
| | `TrailerNoSeparatorError` | `TrailerParser.split` / `TrailerCodecService.decode` when the blank-line guard fails | A trailer block was found without a blank line separating it from the body (see `TrailerParser`). | | ||
| | `TrailerValueInvalidError` | `GitTrailer` via `GitTrailerSchema.parse` when constructing trailers | A trailer value violated the `GitTrailerSchema` (e.g., contained `\n`). | | ||
| | `TrailerInvalidError` | `GitTrailer` via `GitTrailerSchema.parse` when constructing trailers | Trailer key or value failed validation (`GitTrailerSchema`). | | ||
| | `CommitMessageInvalidError` | `GitCommitMessage` via `GitCommitMessageSchema.parse` (triggered by `TrailerCodecService.decode` or `encode`) | The `GitCommitMessageSchema` rejected the title/body/trailers combination. | | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # Architecture: @git-stunts/trailer-codec | ||
|
|
||
| This project adheres to **Hexagonal Architecture** (Ports and Adapters) and **Domain-Driven Design (DDD)** principles to ensure robustness, testability, and separation of concerns. | ||
|
|
||
| ## 🧱 Core Concepts | ||
|
|
||
| ### Domain Layer (`src/domain/`) | ||
| The core business logic, isolated from external frameworks or I/O. | ||
|
|
||
| - **Entities**: Mutable objects with identity and lifecycle (e.g., `GitCommitMessage`). | ||
| - **Value Objects**: Immutable objects defined by their attributes (e.g., `GitTrailer`). | ||
| - **Services**: Domain logic that doesn't fit naturally into an entity (e.g., `TrailerCodecService` for parsing/serializing). | ||
| - **Errors**: Domain-specific error hierarchy (`TrailerCodecError` plus concrete subclasses such as `TrailerNoSeparatorError` and `TrailerValueInvalidError`). | ||
| - **Schemas**: Zod schemas for validation of domain objects. | ||
|
|
||
| ### Ports Layer (`src/ports/`) | ||
| *Currently implicit.* The public API (exported via `index.js`) serves as the primary input port/facade for consumers. Since this library is primarily a data transformation tool (codec), it does not currently have complex output ports for I/O. | ||
|
|
||
| ## 📂 Directory Structure | ||
|
|
||
| ``` | ||
| src/ | ||
| ├── domain/ | ||
| │ ├── entities/ # GitCommitMessage | ||
| │ ├── errors/ # TrailerCodecError and validation subclasses | ||
| │ ├── schemas/ # Zod schemas | ||
| │ ├── services/ # TrailerCodecService | ||
| │ └── value-objects/ # GitTrailer | ||
| ``` | ||
|
|
||
| ## 🧪 Testing Strategy | ||
|
|
||
| - **Unit Tests** (`test/unit/`): Comprehensive tests for entities, value objects, and services. | ||
| - **Test Doubles**: The architecture supports easy mocking of dependencies if the system grows. | ||
|
|
||
| ## 🛠️ Design Decisions | ||
|
|
||
| 1. **Zod for Validation**: We use Zod for runtime schema validation but wrap it in domain-specific `TrailerCodecError` subclasses to avoid leaking implementation details. | ||
| 2. **Case Normalization**: Git trailer keys are case-insensitive. We normalize them to lowercase in the `GitTrailer` Value Object to ensure consistency. | ||
| 3. **Facade Pattern**: `index.js` acts as a facade, providing a simple, backward-compatible API while exposing the rich domain model for advanced users. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.