Gate JSDoc completeness on every package export
New doc-sync gate verify-export-jsdoc walks every module-level exported name under packages/*/*/src and requires description prose everywhere, plus @param per parameter and @returns on non-void annotated returns for function-like exports, public class methods, properties, and accessors. The parsing + check helpers move out of gen-cordis-catalog.ts into a shared scripts/jsdoc.ts so 'documented' means one thing on both gated surfaces. Deliberate exemptions (documented in the RFC): heritage-declared class members (the seam declaration is the doc's one home — the one checker query in an otherwise pure-AST walk), cordis plugin-protocol slots (name/inject/reusable/Config/apply, top-level and static), constructors, overload implementations, declare-module augmentation bodies, and re-export statements (checked at the defining module). The 203 under-documented exports the gate found at adoption are filled in this change, so the gate lands green; generated catalogs/graphs are regenerated for the shifted line pointers. RFC: docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md
This commit is contained in:
@@ -30,6 +30,7 @@ export const name = 'web-fetch-local'
|
||||
/** The web seam this provider registers into. */
|
||||
export const inject = ['web']
|
||||
|
||||
/** Plugin config: the provider's transport and size limits plus its `User-Agent` (all defaulted). */
|
||||
export interface Config {
|
||||
/** Maximum accepted request URL length. */
|
||||
maxUrlLength?: number
|
||||
|
||||
@@ -16,6 +16,10 @@ export type FetchableKind = 'html' | 'text'
|
||||
* enforces before any network access: http(s) only, no embedded credentials,
|
||||
* bounded length. Returns the parsed `URL`. Throws {@link WebError} otherwise.
|
||||
* (SSRF / private-network blocking is deferred — see the package RFC.)
|
||||
*
|
||||
* @param input - the raw URL string from the fetch request.
|
||||
* @param maxUrlLength - inclusive upper bound on `input`'s length.
|
||||
* @returns the parsed `URL`.
|
||||
*/
|
||||
export function validateFetchUrl(input: string, maxUrlLength: number): URL {
|
||||
if (input.length > maxUrlLength) {
|
||||
@@ -40,6 +44,10 @@ export function validateFetchUrl(input: string, maxUrlLength: number): URL {
|
||||
* Two URLs are same-origin when scheme, hostname, and port match. A redirect
|
||||
* that crosses origins is refused so each new origin requires a fresh tool call
|
||||
* (and thus a fresh provider/permission decision).
|
||||
*
|
||||
* @param a - one of the two URLs to compare.
|
||||
* @param b - the other URL to compare.
|
||||
* @returns true when `a` and `b` share scheme, hostname, and port.
|
||||
*/
|
||||
export function isSameOrigin(a: URL, b: URL): boolean {
|
||||
return a.protocol === b.protocol && a.hostname === b.hostname && a.port === b.port
|
||||
@@ -49,6 +57,10 @@ export function isSameOrigin(a: URL, b: URL): boolean {
|
||||
* Classify a response `Content-Type` into a decodable body kind, or `undefined`
|
||||
* for an unsupported (e.g. binary) type. `text/html` and `application/xhtml+xml`
|
||||
* are `html`; other `text/*` plus a few structured text types are `text`.
|
||||
*
|
||||
* @param contentType - the raw `Content-Type` header, or `null` when the
|
||||
* response carries none (unsupported).
|
||||
* @returns the decodable kind, or `undefined` for an unsupported type.
|
||||
*/
|
||||
export function classifyContentType(contentType: string | null): FetchableKind | undefined {
|
||||
const mime = (contentType ?? '').replace(/;.*$/s, '').trim().toLowerCase()
|
||||
@@ -63,6 +75,10 @@ export function classifyContentType(contentType: string | null): FetchableKind |
|
||||
* or `undefined` when absent. The provider feeds this label to `TextDecoder`
|
||||
* so a non-UTF-8 response is decoded with its declared encoding rather than
|
||||
* silently mangled into replacement characters.
|
||||
*
|
||||
* @param contentType - the raw `Content-Type` header, or `null` when the
|
||||
* response carries none.
|
||||
* @returns the lower-cased charset label, or `undefined` when none is declared.
|
||||
*/
|
||||
export function parseCharset(contentType: string | null): string | undefined {
|
||||
const match = /;\s*charset\s*=\s*"?([^";]+)"?/i.exec(contentType ?? '')
|
||||
@@ -74,6 +90,10 @@ export function parseCharset(contentType: string | null): string | undefined {
|
||||
* none is declared. Throws {@link WebError} `WEB_UNSUPPORTED_CONTENT_TYPE` when
|
||||
* the label is present but not a charset `TextDecoder` recognizes — better to
|
||||
* fail loudly than return mojibake.
|
||||
*
|
||||
* @param charset - the declared charset label (from {@link parseCharset}), or
|
||||
* `undefined` to default to UTF-8.
|
||||
* @returns a decoder for the declared (or defaulted) encoding.
|
||||
*/
|
||||
export function decoderForCharset(charset: string | undefined): TextDecoder {
|
||||
if (charset === undefined) return new TextDecoder('utf-8')
|
||||
|
||||
Reference in New Issue
Block a user