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
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Thin caller for the org-wide reusable workflow in `tselect-npm/.github`.
# Every input has a default suited to this toolchain (pnpm + tsdown + Vitest +
# Biome + tsc), so there is nothing to configure here. In particular
# `es-check-target` defaults to es2015, which is this package's declared
# emitted-syntax ceiling — unlike `thrown`, which has to override it to es2016.
#
# The `@v1` pin is deliberate and must never become `@main`: an edit upstream
# would otherwise change all seven repos' CI on their next run with no review in
# any of them. `v1` moves for fixes and backwards-compatible additions; anything
# that could turn a passing build red gets `v2` and repos migrate one at a time.

name: CI

on:
push:
branches: [main]
pull_request:

# Set here rather than in the reusable workflow: inside a reusable workflow
# `github.workflow` and `github.ref` resolve to the caller's, so every repo
# calling it would share one concurrency group and cancel each other.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
ci:
uses: tselect-npm/.github/.github/workflows/ci.yml@v1
64 changes: 64 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Thin caller for the org-wide reusable release workflow in `tselect-npm/.github`.
# Publishing happens here and nowhere else — there is no npm token on anyone's
# laptop once trusted publishing is configured for this package.
#
# **This file must stay named `publish.yml`.** npm's trusted publisher config for
# `@tselect/http-method` names one workflow file, and for a reusable workflow npm
# validates the *caller's* filename rather than the reusable one. Renaming this
# file breaks publishing with a 404 that mentions nothing about filenames.
#
# The `@v1` pin is deliberate and must never become `@main`, for the same reason
# as ci.yml: an edit upstream would otherwise change every repo's release
# behaviour with no review in any of them.

name: Publish

on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump. `auto` reads it from the gitmoji since the last release.'
type: choice
options: [auto, patch, minor, major]
default: auto
dry-run:
description: 'Plan, rehearse the publish, then stop before anything is pushed or published.'
type: boolean
default: false
dist-tag:
description: 'npm dist-tag.'
type: string
default: latest
since-ref:
description: >-
Count commits from this ref instead of the tag matching the published
version. Should not be needed: the @bluejay-era tags were removed and
v1.0.0 recreated at the commit the registry records as 1.0.0's gitHead,
so the range resolves on its own. Leave empty unless it does not.
type: string
default: ''

# A release must never be cancelled by a later one: the tag is pushed before
# `pnpm publish` runs, so an interruption in that window leaves a tagged version
# the registry does not have. Re-running recovers it, but not being interrupted
# is better. Note this differs from ci.yml, where cancelling is the point.
concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: false

jobs:
publish:
permissions:
# Push the release commit and the tag to `main`.
contents: write
# Mint the OIDC token npm exchanges for publish rights. Required *here* as
# well as in the reusable workflow: a called workflow can only narrow the
# permissions it is given, so omitting this produces a job with no token
# and a 404 from the registry.
id-token: write
uses: tselect-npm/.github/.github/workflows/publish.yml@v1
with:
bump: ${{ inputs.bump }}
dry-run: ${{ inputs.dry-run }}
dist-tag: ${{ inputs.dist-tag }}
since-ref: ${{ inputs.since-ref }}
15 changes: 7 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
**/*.js
.idea/
node_modules/
dist/
coverage/
.nyc_output/
*.log
npm-debug.log*
.DS_Store
.idea/
.vscode/
coverage/
dist/
dts/
lib/
node_modules/
npm-debug.log
9 changes: 0 additions & 9 deletions .npmignore

This file was deleted.

10 changes: 0 additions & 10 deletions .travis.yml

This file was deleted.

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017-2026 Sylvain Estevez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
104 changes: 99 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,112 @@
# HTTPMethod
# @tselect/http-method

[![npm](https://img.shields.io/npm/v/@tselect/http-method.svg?style=flat-square)](https://www.npmjs.com/package/@tselect/http-method)
[![npm](https://img.shields.io/npm/dm/@tselect/http-method.svg?style=flat-square)](https://www.npmjs.com/package/@tselect/http-method)
[![npm](https://img.shields.io/npm/l/@tselect/http-method.svg?style=flat-square)](https://www.npmjs.com/package/@tselect/http-method)
[![npm](https://img.shields.io/npm/dm/@tselect/http-method.svg?style=flat-square)](https://www.npmjs.com/package/@tselect/http-method)
[![CI](https://img.shields.io/github/actions/workflow/status/tselect-npm/http-method/ci.yml?branch=main&style=flat-square)](https://github.com/tselect-npm/http-method/actions/workflows/ci.yml)
[![coverage](https://img.shields.io/coverallsCoverage/github/tselect-npm/http-method?branch=main&style=flat-square)](https://coveralls.io/github/tselect-npm/http-method?branch=main)
[![license](https://img.shields.io/npm/l/@tselect/http-method.svg?style=flat-square)](./LICENSE)

HTTP methods related enums and utilities.

Zero runtime dependencies. Ships both ESM and CommonJS builds, with TypeScript types for each.

## Requirements

**Node 22 or newer** (`engines.node` is `>=22`) — every line still receiving security support. Each release is tested on 22, 24 and 26; the declared floor is the lowest version CI actually runs, not a guess.

## Installation

`npm i @tselect/http-method`
```bash
npm i @tselect/http-method
```

```bash
pnpm add @tselect/http-method
```

## Usage

```typescript
import { HTTPMethod, isHTTPMethod } from '@tselect/http-method';

HTTPMethod.GET; // get
HTTPMethod.GET; // 'get'
isHTTPMethod(HTTPMethod.GET); // true
```

Namespace imports and `require()` both work:

```typescript
import * as HTTPMethodUtils from '@tselect/http-method';
```

```javascript
const { HTTPMethod, isHTTPMethod } = require('@tselect/http-method');
```

## API

### `HTTPMethod`

A string enum of the supported HTTP methods. Every member's value is lower case.

```typescript
HTTPMethod.GET; // 'get'
HTTPMethod.POST; // 'post'
HTTPMethod.PATCH; // 'patch'
HTTPMethod.DELETE; // 'delete'
HTTPMethod.HEAD; // 'head'
HTTPMethod.OPTIONS; // 'options'
HTTPMethod.PUT; // 'put'
```

### `THTTPMethod`

A union of every method name in both lower and constant case — `'get' | 'post' | … | 'GET' | 'POST' | …`. Every function below accepts it, so the enum, a lower case literal and a constant case literal are all valid arguments.

```typescript
import type { THTTPMethod } from '@tselect/http-method';

const method: THTTPMethod = 'PATCH';
```

### `isHTTPMethod(candidate: string): boolean`

Returns whether an arbitrary string names an HTTP method. Case-insensitive, and unlike the functions below it accepts any `string`, so it is the one to reach for when validating untrusted input.

```typescript
isHTTPMethod('get'); // true
isHTTPMethod('GET'); // true
isHTTPMethod('gEt'); // true
isHTTPMethod('foo'); // false
```

### `toLowerCase(method: THTTPMethod): THTTPMethod`

Returns the lower case form, which is the form the `HTTPMethod` enum uses.

```typescript
toLowerCase('GET'); // 'get'
toLowerCase('get'); // 'get'
```

### `toConstantCase(method: THTTPMethod): THTTPMethod`

Returns the upper case form, as used in most HTTP tooling and in the `Allow` header.

```typescript
toConstantCase('get'); // 'GET'
toConstantCase('GET'); // 'GET'
```

### `toPascalCase(method: THTTPMethod): string`

Returns the method with its first character upper cased and the rest lower cased. Useful for building method-derived identifiers such as `onGet` or `handlePost`.

```typescript
toPascalCase('get'); // 'Get'
toPascalCase('POST'); // 'Post'
```

## License

[MIT](./LICENSE) © Sylvain Estevez
40 changes: 40 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "https://biomejs.dev/schemas/2.5.8/schema.json",
"files": {
"includes": ["**", "!dist", "!coverage"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 120,
"includes": ["**", "!package.json"]
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "always",
"trailingCommas": "all"
}
},
"linter": {
"enabled": true,
"rules": {
"preset": "recommended",
"complexity": {
"noArguments": "error"
},
"suspicious": {
"noConsole": { "level": "error", "options": { "allow": ["warn", "error"] } },
"noDoubleEquals": "error"
}
}
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}
Loading