diff --git a/_tools/check_docs.ts b/_tools/check_docs.ts index 92a5faa09..6a2ddb04c 100644 --- a/_tools/check_docs.ts +++ b/_tools/check_docs.ts @@ -1,11 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. /** - * This script checks that all exported functions have JSDoc comments with - * `@param`, `@return`, and `@example` tags, according to the contributing - * guidelines. - * - * @see {@link https://github.com/denoland/deno_std/blob/main/.github/CONTRIBUTING.md#documentation} + * This script checks that all public symbols documentation aligns with the + * {@link ./CONTRIBUTING.md#documentation | documentation guidelines}. * * TODO(iuioiua): Add support for classes and methods. */ @@ -13,10 +10,14 @@ import { doc, type DocNodeBase, type DocNodeFunction, - type JsDocTag, + type JsDoc, type JsDocTagDocRequired, } from "@deno/doc"; +type DocNodeWithJsDoc = T & { + jsDoc: JsDoc; +}; + const ENTRY_POINTS = [ "../bytes/mod.ts", "../datetime/mod.ts", @@ -46,36 +47,34 @@ function assert( } } -/** - * We only check functions that have JSDocs. We know that exported functions - * have JSDocs thanks to `deno doc --lint`, which is used in the `lint:docs` - * task. - */ -function isFunctionDoc(document: DocNodeBase): document is DocNodeFunction { - return document.kind === "function" && document.jsDoc !== undefined; -} - function isExported(document: DocNodeBase) { return document.declarationKind === "export"; } -function assertHasTag(tags: JsDocTag[], kind: string, document: DocNodeBase) { - const tag = tags.find((tag) => tag.kind === kind); - assert(tag !== undefined, `Symbol must have a @${kind} tag`, document); +function isFunctionDoc( + document: DocNodeBase, +): document is DocNodeWithJsDoc { + return document.kind === "function" && document.jsDoc !== undefined; +} + +function assertHasReturnTag(document: DocNodeWithJsDoc) { + const tag = document.jsDoc.tags?.find((tag) => tag.kind === "return"); + assert(tag !== undefined, "Symbol must have a @return tag", document); assert( // @ts-ignore doc is defined tag.doc !== undefined, - `@${kind} tag must have a description`, + "@return tag must have a description", document, ); } function assertHasParamTag( - tags: JsDocTag[], + document: DocNodeWithJsDoc, param: string, - document: DocNodeBase, ) { - const tag = tags.find((tag) => tag.kind === "param" && tag.name === param); + const tag = document.jsDoc.tags?.find((tag) => + tag.kind === "param" && tag.name === param + ); assert( tag !== undefined, `Symbol must have a @param tag for ${param}`, @@ -89,9 +88,9 @@ function assertHasParamTag( ); } -function assertHasExampleTag(tags: JsDocTag[], document: DocNodeBase) { - tags = tags.filter((tag) => tag.kind === "example"); - if (tags.length === 0) { +function assertHasExampleTag(document: DocNodeWithJsDoc) { + const tags = document.jsDoc.tags?.filter((tag) => tag.kind === "example"); + if (tags === undefined || tags.length === 0) { throw new DocumentError("Symbol must have an @example tag", document); } for (const tag of (tags as JsDocTagDocRequired[])) { @@ -130,11 +129,10 @@ function assertHasExampleTag(tags: JsDocTag[], document: DocNodeBase) { } function assertHasTypeParamTags( - tags: JsDocTag[], + document: DocNodeWithJsDoc, typeParamName: string, - document: DocNodeBase, ) { - const tag = tags.find((tag) => + const tag = document.jsDoc.tags?.find((tag) => tag.kind === "template" && tag.name === typeParamName ); assert( @@ -150,28 +148,29 @@ function assertHasTypeParamTags( ); } -function assertFunctionDocs(document: DocNodeFunction) { - assert( - document.jsDoc !== undefined, - "Symbol must have a JSDoc block", - document, - ); - const { tags } = document.jsDoc; - assert(tags !== undefined, "JSDoc block must have tags", document); +/** + * Asserts that a function document has: + * - A `@typeParam` tag for each type parameter. + * - A {@linkcode https://jsdoc.app/tags-param | @param} tag for each parameter. + * - A {@linkcode https://jsdoc.app/tags-returns | @returns} tag. + * - At least one {@linkcode https://jsdoc.app/tags-example | @example} tag with + * a code snippet that executes successfully. + */ +function assertFunctionDocs(document: DocNodeWithJsDoc) { for (const param of document.functionDef.params) { if (param.kind === "identifier") { - assertHasParamTag(tags, param.name, document); + assertHasParamTag(document, param.name); } if (param.kind === "assign") { // @ts-ignore Trust me - assertHasParamTag(tags, param.left.name, document); + assertHasParamTag(document, param.left.name); } } for (const typeParam of document.functionDef.typeParams) { - assertHasTypeParamTags(tags, typeParam.name, document); + assertHasTypeParamTags(document, typeParam.name); } - assertHasTag(tags, "return", document); - assertHasExampleTag(tags, document); + assertHasReturnTag(document); + assertHasExampleTag(document); } async function checkDocs(specifier: string) { diff --git a/deno.json b/deno.json index 9e1f9cc52..e1be71e2e 100644 --- a/deno.json +++ b/deno.json @@ -19,7 +19,7 @@ "lint:circular": "deno run --allow-env --allow-read --allow-net=deno.land,jsr.io ./_tools/check_circular_package_dependencies.ts", "lint:mod-exports": "deno run --allow-env --allow-read ./_tools/check_mod_exports.ts", "lint:tools-types": "deno check _tools/*.ts", - "lint:docs": "deno run -A _tools/check_docs.ts && deno doc --lint collections/mod.ts bytes/mod.ts datetime/mod.ts internal/mod.ts media_types/mod.ts url/mod.ts", + "lint:docs": "deno doc --lint collections/mod.ts bytes/mod.ts datetime/mod.ts internal/mod.ts media_types/mod.ts url/mod.ts && deno run -A _tools/check_docs.ts", "lint": "deno lint && deno task fmt:licence-headers --check && deno task lint:circular && deno task lint:deprecations && deno task lint:tools-types && deno task lint:mod-exports && deno task lint:docs", "typos": "typos -c ./.github/workflows/typos.toml", "build:crypto": "deno task --cwd crypto/_wasm wasmbuild", diff --git a/media_types/extensions_by_type.ts b/media_types/extensions_by_type.ts index e97266b8e..303199b05 100644 --- a/media_types/extensions_by_type.ts +++ b/media_types/extensions_by_type.ts @@ -4,8 +4,6 @@ import { parseMediaType } from "./parse_media_type.ts"; import { extensions } from "./_db.ts"; -export { extensions }; - /** * Returns the extensions known to be associated with the media type `type`, or * `undefined` if no extensions are found.