Skip to content

Commit 6b74d90

Browse files
authored
chore: update doc linter, replace hardcoded entry list with dynamically created one (#6491)
1 parent 536e858 commit 6b74d90

File tree

14 files changed

+143
-179
lines changed

14 files changed

+143
-179
lines changed

_tools/check_docs.ts

Lines changed: 45 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -23,132 +23,48 @@ import {
2323
type Location,
2424
type TsTypeDef,
2525
} from "@deno/doc";
26-
import { pooledMap } from "@std/async/pool";
26+
import { walk } from "@std/fs/walk";
27+
import { join } from "@std/path/join";
28+
import { distinctBy } from "@std/collections/distinct-by";
29+
import { toFileUrl } from "@std/path/to-file-url";
2730

2831
type DocNodeWithJsDoc<T = DocNodeBase> = T & {
2932
jsDoc: JsDoc;
3033
};
3134

32-
const ENTRY_POINTS = [
33-
"../assert/mod.ts",
34-
"../assert/unstable_never.ts",
35-
"../async/mod.ts",
36-
"../bytes/mod.ts",
37-
"../cache/mod.ts",
38-
"../cbor/mod.ts",
39-
"../cli/mod.ts",
40-
"../cli/unstable_spinner.ts",
41-
"../cli/unstable_prompt_multiple_select.ts",
42-
"../crypto/mod.ts",
43-
"../collections/mod.ts",
44-
"../csv/mod.ts",
45-
"../csv/unstable_stringify.ts",
46-
"../data_structures/mod.ts",
47-
"../data_structures/unstable_bidirectional_map.ts",
48-
"../datetime/mod.ts",
49-
"../dotenv/mod.ts",
50-
"../encoding/mod.ts",
51-
"../encoding/unstable_hex.ts",
52-
"../encoding/unstable_base32.ts",
53-
"../encoding/unstable_base64.ts",
54-
"../encoding/unstable_hex.ts",
55-
"../encoding/unstable_base64_stream.ts",
56-
"../encoding/unstable_base32_stream.ts",
57-
"../encoding/unstable_hex_stream.ts",
58-
"../expect/mod.ts",
59-
"../fmt/bytes.ts",
60-
"../fmt/colors.ts",
61-
"../fmt/duration.ts",
62-
"../fmt/printf.ts",
63-
"../front_matter/mod.ts",
64-
"../front_matter/unstable_yaml.ts",
65-
"../fs/mod.ts",
66-
"../fs/unstable_chmod.ts",
67-
"../fs/unstable_copy_file.ts",
68-
"../fs/unstable_link.ts",
69-
"../fs/unstable_lstat.ts",
70-
"../fs/unstable_make_temp_dir.ts",
71-
"../fs/unstable_make_temp_file.ts",
72-
"../fs/unstable_mkdir.ts",
73-
"../fs/unstable_read_dir.ts",
74-
"../fs/unstable_read_file.ts",
75-
"../fs/unstable_read_link.ts",
76-
"../fs/unstable_read_text_file.ts",
77-
"../fs/unstable_real_path.ts",
78-
"../fs/unstable_remove.ts",
79-
"../fs/unstable_rename.ts",
80-
"../fs/unstable_stat.ts",
81-
"../fs/unstable_symlink.ts",
82-
"../fs/unstable_truncate.ts",
83-
"../fs/unstable_types.ts",
84-
"../fs/unstable_umask.ts",
85-
"../fs/unstable_utime.ts",
86-
"../fs/unstable_write_file.ts",
87-
"../fs/unstable_write_text_file.ts",
88-
"../html/mod.ts",
89-
"../html/unstable_is_valid_custom_element_name.ts",
90-
"../http/mod.ts",
91-
"../http/unstable_header.ts",
92-
"../http/unstable_method.ts",
93-
"../http/unstable_signed_cookie.ts",
94-
"../ini/mod.ts",
95-
"../internal/mod.ts",
96-
"../io/mod.ts",
97-
"../json/mod.ts",
98-
"../jsonc/mod.ts",
99-
"../log/base_handler.ts",
100-
"../log/file_handler.ts",
101-
"../log/warn.ts",
102-
"../log/critical.ts",
103-
"../log/debug.ts",
104-
"../log/error.ts",
105-
"../log/info.ts",
106-
"../log/console_handler.ts",
107-
"../log/formatters.ts",
108-
"../log/get_logger.ts",
109-
"../log/logger.ts",
110-
"../media_types/mod.ts",
111-
"../msgpack/mod.ts",
112-
"../net/mod.ts",
113-
"../net/unstable_get_network_address.ts",
114-
"../path/mod.ts",
115-
"../path/unstable_basename.ts",
116-
"../path/unstable_dirname.ts",
117-
"../path/unstable_extname.ts",
118-
"../path/unstable_join.ts",
119-
"../path/unstable_normalize.ts",
120-
"../path/posix/mod.ts",
121-
"../path/windows/mod.ts",
122-
"../random/mod.ts",
123-
"../regexp/mod.ts",
124-
"../semver/mod.ts",
125-
"../streams/mod.ts",
126-
"../streams/unstable_fixed_chunk_stream.ts",
127-
"../streams/unstable_to_lines.ts",
128-
"../streams/unstable_to_bytes.ts",
129-
"../tar/mod.ts",
130-
"../text/mod.ts",
131-
"../text/unstable_slugify.ts",
132-
"../text/unstable_to_constant_case.ts",
133-
"../testing/bdd.ts",
134-
"../testing/mock.ts",
135-
"../testing/snapshot.ts",
136-
"../testing/time.ts",
137-
"../testing/types.ts",
138-
"../toml/mod.ts",
139-
"../ulid/mod.ts",
140-
"../uuid/mod.ts",
141-
"../uuid/unstable_v7.ts",
142-
"../webgpu/mod.ts",
143-
"../yaml/mod.ts",
144-
] as const;
35+
const ROOT = new URL("../", import.meta.url);
36+
const ENTRY_POINT_URLS = [];
37+
for await (
38+
const { path } of walk(ROOT, { exts: [".json"], match: [/deno.json$/] })
39+
) {
40+
const { exports } = await Deno.readTextFile(path).then(JSON.parse);
41+
42+
if (!exports) continue;
43+
for (const relativeFilePath of Object.values<string>(exports)) {
44+
if (!relativeFilePath.endsWith(".ts")) continue;
45+
46+
const filePath = join(path, "..", relativeFilePath);
47+
48+
// Ignores 4 files in @std/log package
49+
if (
50+
/log[/\\](mod|levels|setup|rotating_file_handler)\.ts$/.test(filePath)
51+
) {
52+
// deno-lint-ignore no-console
53+
console.warn(
54+
`Doc check for ${filePath} is ignored. Visit https://github.com/denoland/std/issues/6124 for more details.`,
55+
);
56+
continue;
57+
}
58+
59+
ENTRY_POINT_URLS.push(toFileUrl(filePath).href);
60+
}
61+
}
14562

14663
const TS_SNIPPET = /```ts[\s\S]*?```/g;
14764
const ASSERTION_IMPORT =
14865
/from "@std\/(assert(\/[a-z-]+)?|testing\/(mock|snapshot|types))"/g;
14966
const NEWLINE = "\n";
15067
const diagnostics: DocumentError[] = [];
151-
const snippetPromises: (() => Promise<void>)[] = [];
15268

15369
class DocumentError extends Error {
15470
constructor(
@@ -274,10 +190,8 @@ function assertSnippetsWork(
274190
document,
275191
),
276192
);
277-
return;
278-
} else {
279-
return;
280193
}
194+
return;
281195
}
282196
for (let snippet of snippets) {
283197
const delim = snippet.split(NEWLINE)[0];
@@ -413,7 +327,9 @@ function assertClassDocs(document: DocNodeWithJsDoc<DocNodeClass>) {
413327
for (const typeParam of document.classDef.typeParams) {
414328
assertHasTypeParamTags(document, typeParam.name);
415329
}
416-
assertHasExampleTag(document);
330+
if (!document.jsDoc.tags?.some((tag) => tag.kind === "example")) {
331+
assertHasExampleTag(document);
332+
}
417333

418334
for (const property of document.classDef.properties) {
419335
if (property.jsDoc === undefined) continue; // this is caught by `deno doc --lint`
@@ -547,10 +463,13 @@ async function checkDocs(specifier: string) {
547463
const docs = (await doc([specifier], { resolve }))[specifier]!;
548464
for (const d of docs.filter(isExported)) {
549465
if (d.jsDoc === undefined) continue; // this is caught by other checks
466+
550467
const document = d as DocNodeWithJsDoc<DocNode>;
551468
switch (document.kind) {
552469
case "moduleDoc": {
553-
assertModuleDoc(document);
470+
if (document.location.filename.endsWith("/mod.ts")) {
471+
assertModuleDoc(document);
472+
}
554473
break;
555474
}
556475
case "function": {
@@ -567,10 +486,6 @@ async function checkDocs(specifier: string) {
567486
}
568487
}
569488

570-
const ENTRY_POINT_URLS = ENTRY_POINTS.map((entry) =>
571-
new URL(entry, import.meta.url).href
572-
);
573-
574489
const lintStatus = await new Deno.Command(Deno.execPath(), {
575490
args: ["doc", "--lint", ...ENTRY_POINT_URLS],
576491
stdin: "inherit",
@@ -587,18 +502,13 @@ if (!lintStatus.success) {
587502
Deno.exit(1);
588503
}
589504

590-
await Promise.all(ENTRY_POINT_URLS.map(checkDocs));
591-
592-
const iter = pooledMap(
593-
navigator.hardwareConcurrency,
594-
snippetPromises,
595-
(fn) => fn(),
596-
);
597-
for await (const _ of iter) {
598-
// noop
505+
for (const url of ENTRY_POINT_URLS) {
506+
await checkDocs(url);
599507
}
508+
600509
if (diagnostics.length > 0) {
601-
for (const error of diagnostics) {
510+
const errors = distinctBy(diagnostics, (e) => e.message + e.cause);
511+
for (const error of errors) {
602512
// deno-lint-ignore no-console
603513
console.error(
604514
`%c[error] %c${error.message} %cat ${error.cause}`,
@@ -609,6 +519,6 @@ if (diagnostics.length > 0) {
609519
}
610520

611521
// deno-lint-ignore no-console
612-
console.log(`%c${diagnostics.length} errors found`, "color: red");
522+
console.log(`%c${errors.length} errors found`, "color: red");
613523
Deno.exit(1);
614524
}

_tools/check_mod_exports.ts

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,13 @@ import { relative } from "../path/relative.ts";
66
import { dirname } from "../path/dirname.ts";
77
import * as colors from "../fmt/colors.ts";
88
import ts from "npm:typescript";
9+
import { isTestFile } from "./utils.ts";
910

1011
const ROOT = new URL("../", import.meta.url);
1112
const FAIL_FAST = Deno.args.includes("--fail-fast");
1213

1314
let shouldFail = false;
1415

15-
function hasExports(filePath: string): boolean {
16-
const source = Deno.readTextFileSync(filePath);
17-
const sourceFile = ts.createSourceFile(
18-
filePath,
19-
source,
20-
ts.ScriptTarget.Latest,
21-
);
22-
23-
let result = false;
24-
25-
function visitNode(node: ts.Node) {
26-
if (
27-
ts.isExportSpecifier(node) ||
28-
ts.isExportAssignment(node) ||
29-
ts.isExportDeclaration(node) ||
30-
node.kind === ts.SyntaxKind.ExportKeyword
31-
) {
32-
result = true;
33-
} else {
34-
ts.forEachChild(node, visitNode);
35-
}
36-
}
37-
38-
visitNode(sourceFile);
39-
40-
return result;
41-
}
42-
4316
for await (
4417
const { path: modFilePath } of walk(ROOT, {
4518
includeDirs: true,
@@ -95,8 +68,7 @@ for await (
9568
.replaceAll("\\", "/");
9669

9770
if (!modExportSpecifiers.has(relativeSpecifier)) {
98-
// ignore test.ts files have no exports (which means that are Deno.test() files)
99-
if (relativeSpecifier === "./test.ts" && !hasExports(filePath)) continue;
71+
if (isTestFile(filePath)) continue;
10072

10173
console.warn(
10274
`${

_tools/utils.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Copyright 2018-2025 the Deno authors. MIT license.
22

3+
import ts from "npm:typescript";
4+
35
const workspaces = JSON.parse(await Deno.readTextFile("deno.json"))
46
.workspace as string[];
57
// deno-lint-ignore no-explicit-any
@@ -34,3 +36,37 @@ export function resolveWorkspaceSpecifiers(
3436
return new URL(specifier).href;
3537
}
3638
}
39+
40+
/**
41+
* Checks whether a file is named `test.ts` and has no exports.
42+
* @param filePath
43+
* @returns true if file is named `test.ts` and has no exports, false otherwise
44+
*/
45+
export function isTestFile(filePath: string): boolean {
46+
if (!filePath.endsWith("test.ts")) return false;
47+
const source = Deno.readTextFileSync(filePath);
48+
const sourceFile = ts.createSourceFile(
49+
filePath,
50+
source,
51+
ts.ScriptTarget.Latest,
52+
);
53+
54+
let result = true;
55+
56+
function visitNode(node: ts.Node) {
57+
if (!result) return;
58+
if (
59+
ts.isExportSpecifier(node) ||
60+
ts.isExportAssignment(node) ||
61+
ts.isExportDeclaration(node) ||
62+
node.kind === ts.SyntaxKind.ExportKeyword
63+
) {
64+
result = false;
65+
} else {
66+
ts.forEachChild(node, visitNode);
67+
}
68+
}
69+
70+
visitNode(sourceFile);
71+
return result;
72+
}

cli/unstable_progress_bar.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ export interface ProgressBarOptions {
8282
* Default Style: `[mm:ss] [###-------] [0.24/97.6 KiB]`.
8383
*/
8484
fmt?: (fmt: ProgressBarFormatter) => string;
85+
/**
86+
* Whether the writable should be kept open when progress bar stops.
87+
* @default {true}
88+
*/
8589
keepOpen?: boolean;
8690
}
8791

@@ -242,6 +246,13 @@ export class ProgressBar {
242246
/**
243247
* Increments the progress by `x`.
244248
*
249+
* @example Usage
250+
* ```ts ignore
251+
* import { ProgressBar } from "@std/cli/unstable-progress-bar";
252+
*
253+
* const progressBar = new ProgressBar(Deno.stdout.writable, { max: 100 });
254+
* progressBar.add(10);
255+
* ```
245256
* @param x The amount of progress that has been made.
246257
*/
247258
add(x: number): void {
@@ -250,6 +261,14 @@ export class ProgressBar {
250261

251262
/**
252263
* Ends the progress bar and cleans up any lose ends.
264+
*
265+
* @example Usage
266+
* ```ts ignore
267+
* import { ProgressBar } from "@std/cli/unstable-progress-bar";
268+
*
269+
* const progressBar = new ProgressBar(Deno.stdout.writable, { max: 100 });
270+
* await progressBar.end()
271+
* ```
253272
*/
254273
async end(): Promise<void> {
255274
clearInterval(this.#id);

0 commit comments

Comments
 (0)