fix review findings: close wrapped-expression, alias, and binding-pattern gaps
Codex round-2 review found three adjacent fail-open shapes: - Wrapped function expressions escaped classification: parentheses, as/satisfies casts, and non-null assertions are now peeled before the arrow/function test (initializers and default exports), and a single-call-signature type literal counts as the surface signature. A literal mixing call/construct signatures with anything else is refused outright — no single signature to hold the tags against. - The blanket 'export import X = N.member' skip was unsound (the target can be a non-exported namespace member no walk visits): an alias now documents itself. - The heritage extra-parameter duty missed binding-pattern extras, which no base declaration can name: they now trigger the standard binding-pattern violation. Five new negative-path tests pin the closed shapes; module doc and RFC updated.
This commit is contained in:
@@ -13,12 +13,12 @@ A new gate, `scripts/verify-export-jsdoc.ts` (`pnpm run verify-export-jsdoc`, wi
|
||||
The contract by declaration kind:
|
||||
|
||||
- Every exported name needs JSDoc with non-empty description prose.
|
||||
- Function-like exports (function declarations; consts with function initializers or an INLINE function-type annotation; non-identifier function default exports) follow the full function contract. A const whose declarator is annotated with a NAMED type (`export const f: Handler = …`) defers the signature contract to that type's own declaration and `@returns` stays optional; an inline `(x: T) => U` annotation is the surface signature itself and gets the full contract.
|
||||
- Function-like exports (function declarations; consts with function initializers or an INLINE callable annotation; non-identifier function default exports) follow the full function contract, with wrapper expressions (parentheses, `as`/`satisfies` casts, non-null assertions) peeled before classifying. A const whose declarator is annotated with a NAMED type (`export const f: Handler = …`) defers the signature contract to that type's own declaration and `@returns` stays optional; an inline `(x: T) => U` annotation or single-call-signature literal is the surface signature itself and gets the full contract, and a literal mixing call/construct signatures with anything else is refused outright (no single signature to hold the tags against — extract a named type).
|
||||
- Exported classes need class-level prose; public methods (statics included — reachable on the exported name) follow the function contract; public properties and accessors need prose (a get/set pair is covered by the getter). Overload implementations are exempt — the signatures carry the docs.
|
||||
- Exported interfaces, type aliases, and enums need prose on the declaration; member-level enforcement is deliberately deferred (the highest-value member surface — seam service classes — is already under the cordis gate).
|
||||
- Exported namespaces recurse (inside an ambient `declare` namespace every member exports implicitly); the namespace itself needs prose only when it does not merge with a documented same-name declaration (the Config-namespace idiom documents the plugin once).
|
||||
- `declare module` / `declare global` bodies, `export … from` re-export statements, and `export import X = N.member` aliases are skipped: an augmentation is not an export of the package, and a re-exported or aliased definition is checked where it is defined.
|
||||
- Everything else fails CLOSED: `export =` is refused outright, and an exported statement kind the dispatch does not recognize is itself a violation — no export form can pass unchecked by omission.
|
||||
- `declare module` / `declare global` bodies and `export … from` re-export statements are skipped: an augmentation is not an export of the package, and a re-exported definition is checked where it is defined. An `export import X = N.member` alias documents ITSELF — its target may be a non-exported namespace member no walk visits, so the "definition owns the doc" rationale does not hold for it.
|
||||
- Everything else fails CLOSED: `export =` is refused outright, parameters the base never names keep their `@param` duty even as binding patterns, and an exported statement kind the dispatch does not recognize is itself a violation — no export form can pass unchecked by omission.
|
||||
|
||||
Three exemption families keep the gate from demanding boilerplate, in the spirit of the cordis gate's `this`/`next` exemptions (documenting an exempt name anyway is allowed; only absence goes unchecked):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user