first commit
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# parse-uri
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`parseUri(uri)` is the RFC 3986 subset parser the resolver uses to extract a
|
||||
scheme, optional authority, path, and optional query from a URI string. It
|
||||
exists to keep `StorageUriResolver` scheme-agnostic — every adapter plugin
|
||||
owns its own scheme-specific addressing and composes against this base
|
||||
parser.
|
||||
|
||||
The parser intentionally rejects more inputs than RFC 3986 strictly
|
||||
requires: whitespace, NUL bytes, and strings longer than 4096 characters are
|
||||
all hard-failures. The 4096-cap matches the de-facto path-length ceiling
|
||||
observed across S3, Rackspace, Bunny, and most filesystems and prevents
|
||||
quadratic blow-ups inside plugin parsers.
|
||||
|
||||
## Features
|
||||
|
||||
- Scheme regex `^[A-Za-z][A-Za-z0-9+\-.]*$` per RFC 3986 §3.1.
|
||||
- Case-insensitive scheme — the returned `scheme` is lower-cased.
|
||||
- Authority extraction when the rest starts with `//`.
|
||||
- Query/fragment split with both kept off the path.
|
||||
- Single error code on rejection: `STORAGE_URI.INVALID_URI` with the
|
||||
offending input on the `uri` discriminant.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parseUri } from "@suaveplan/storage-uri/parse-uri";
|
||||
|
||||
const parts = parseUri("s3://bucket/raw/clip.mov");
|
||||
// { scheme: "s3", authority: "bucket", path: "/raw/clip.mov" }
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { parseUri } from "@suaveplan/storage-uri/parse-uri";
|
||||
import { STORAGE_URI_CODES, StorageUriError } from "@suaveplan/storage-uri/error-codes";
|
||||
|
||||
function parseOrNull(uri: string) {
|
||||
try {
|
||||
return parseUri(uri);
|
||||
} catch (err) {
|
||||
if (err instanceof StorageUriError && err.code === STORAGE_URI_CODES.INVALID_URI) {
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `interface ParsedUriParts { scheme: string; authority?: string; path: string; query?: string }`
|
||||
- `function parseUri(uri: string): ParsedUriParts` — throws
|
||||
`StorageUriError(STORAGE_URI.INVALID_URI)` on rejection.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Authority termination is hand-rolled instead of regex-based so the parser
|
||||
avoids re-walking the input. The `findAuthorityEnd` helper scans for the
|
||||
first `/`, `?`, or `#` character — these are the three RFC 3986 component
|
||||
delimiters that may follow an authority. Empty path is permitted (e.g.
|
||||
`s3://bucket`); empty rest after the colon (`scheme:`) is not. The
|
||||
maximum-length check happens BEFORE the regex test so pathological inputs
|
||||
cannot pin a regex engine.
|
||||
Reference in New Issue
Block a user