mirror of
https://github.com/denoland/std.git
synced 2024-11-21 12:40:03 +00:00
docs(assert,cli,data-structures,expect,fmt,front-matter,html,http,jsonc,semver,streams,text,toml,webgpu): add snippet checks in module, function and class docs to doc checker (#4855)
* chore: add snippet checks to module docs * fix * work * tweak
This commit is contained in:
parent
3fbdd93691
commit
79d6a70729
@ -15,6 +15,7 @@ import {
|
||||
type DocNodeBase,
|
||||
type DocNodeClass,
|
||||
type DocNodeFunction,
|
||||
type DocNodeModuleDoc,
|
||||
type JsDoc,
|
||||
type JsDocTagDocRequired,
|
||||
type Location,
|
||||
@ -139,17 +140,78 @@ function assertHasParamTag(
|
||||
}
|
||||
}
|
||||
|
||||
async function assertSnippetEvals(
|
||||
snippet: string,
|
||||
document: { jsDoc: JsDoc; location: Location },
|
||||
) {
|
||||
const command = new Deno.Command(Deno.execPath(), {
|
||||
args: [
|
||||
"eval",
|
||||
"--ext=ts",
|
||||
"--unstable-webgpu",
|
||||
snippet,
|
||||
],
|
||||
stderr: "piped",
|
||||
});
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.warn(
|
||||
`Snippet at ${document.location.filename}:${document.location.line} has been running for more than 10 seconds...`,
|
||||
);
|
||||
console.warn(snippet);
|
||||
}, 10_000);
|
||||
try {
|
||||
const { success, stderr } = await command.output();
|
||||
const error = new TextDecoder().decode(stderr);
|
||||
assert(
|
||||
success,
|
||||
`Failed to execute snippet: \n${snippet}\n${error}`,
|
||||
document,
|
||||
);
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
function assertSnippetsWork(
|
||||
doc: string,
|
||||
document: { jsDoc: JsDoc; location: Location },
|
||||
required = true,
|
||||
) {
|
||||
const snippets = doc.match(TS_SNIPPET);
|
||||
if (snippets === null) {
|
||||
if (required) {
|
||||
diagnostics.push(
|
||||
new DocumentError(
|
||||
"@example tag must have a TypeScript code snippet",
|
||||
document,
|
||||
),
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (let snippet of snippets) {
|
||||
if (snippet.split(NEWLINE)[0]?.includes("no-eval")) continue;
|
||||
// Trim the code block delimiters
|
||||
snippet = snippet.split(NEWLINE).slice(1, -1).join(NEWLINE);
|
||||
snippetPromises.push(assertSnippetEvals(snippet, document));
|
||||
}
|
||||
}
|
||||
|
||||
function assertHasExampleTag(
|
||||
document: { jsDoc: JsDoc; location: Location },
|
||||
) {
|
||||
const tags = document.jsDoc.tags?.filter((tag) => tag.kind === "example");
|
||||
const tags = document.jsDoc.tags?.filter((tag) =>
|
||||
tag.kind === "example"
|
||||
) as JsDocTagDocRequired[];
|
||||
if (tags === undefined || tags.length === 0) {
|
||||
diagnostics.push(
|
||||
new DocumentError("Symbol must have an @example tag", document),
|
||||
);
|
||||
return;
|
||||
}
|
||||
for (const tag of (tags as JsDocTagDocRequired[])) {
|
||||
for (const tag of tags) {
|
||||
assert(
|
||||
tag.doc !== undefined,
|
||||
"@example tag must have a title and TypeScript code snippet",
|
||||
@ -164,48 +226,7 @@ function assertHasExampleTag(
|
||||
"@example tag must have a title",
|
||||
document,
|
||||
);
|
||||
const snippets = tag.doc.match(TS_SNIPPET);
|
||||
if (snippets === null) {
|
||||
diagnostics.push(
|
||||
new DocumentError(
|
||||
"@example tag must have a TypeScript code snippet",
|
||||
document,
|
||||
),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
for (let snippet of snippets) {
|
||||
if (snippet.split(NEWLINE)[0]?.includes("no-eval")) continue;
|
||||
// Trim the code block delimiters
|
||||
snippet = snippet.split(NEWLINE).slice(1, -1).join(NEWLINE);
|
||||
const command = new Deno.Command(Deno.execPath(), {
|
||||
args: [
|
||||
"eval",
|
||||
"--ext=ts",
|
||||
"--unstable-webgpu",
|
||||
snippet,
|
||||
],
|
||||
stderr: "piped",
|
||||
});
|
||||
snippetPromises.push((async () => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.warn("Snippet has been running for more than 10 seconds...");
|
||||
console.warn(snippet);
|
||||
}, 10_000);
|
||||
try {
|
||||
const { success, stderr } = await command.output();
|
||||
assert(
|
||||
success,
|
||||
`Example code snippet failed to execute: \n${snippet}\n${
|
||||
new TextDecoder().decode(stderr)
|
||||
}`,
|
||||
document,
|
||||
);
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
})());
|
||||
}
|
||||
assertSnippetsWork(tag.doc, document);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,6 +265,7 @@ function assertHasTypeParamTags(
|
||||
function assertFunctionDocs(
|
||||
document: DocNodeWithJsDoc<DocNodeFunction | ClassMethodDef>,
|
||||
) {
|
||||
assertSnippetsWork(document.jsDoc.doc!, document, false);
|
||||
for (const param of document.functionDef.params) {
|
||||
if (param.kind === "identifier") {
|
||||
assertHasParamTag(document, param.name);
|
||||
@ -273,6 +295,7 @@ function assertFunctionDocs(
|
||||
* - Documentation on all properties, methods, and constructors.
|
||||
*/
|
||||
function assertClassDocs(document: DocNodeWithJsDoc<DocNodeClass>) {
|
||||
assertSnippetsWork(document.jsDoc.doc!, document, false);
|
||||
for (const typeParam of document.classDef.typeParams) {
|
||||
assertHasTypeParamTags(document, typeParam.name);
|
||||
}
|
||||
@ -358,6 +381,14 @@ function assertConstructorDocs(
|
||||
assertHasExampleTag(constructor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a module document for:
|
||||
* - Code snippets that execute successfully.
|
||||
*/
|
||||
function assertModuleDoc(document: DocNodeWithJsDoc<DocNodeModuleDoc>) {
|
||||
assertSnippetsWork(document.jsDoc.doc!, document);
|
||||
}
|
||||
|
||||
function resolve(specifier: string, referrer: string): string {
|
||||
if (specifier.startsWith("@std/") && specifier.split("/").length > 2) {
|
||||
specifier = specifier.replace("@std/", "../").replaceAll("-", "_") + ".ts";
|
||||
@ -371,6 +402,10 @@ async function checkDocs(specifier: string) {
|
||||
if (d.jsDoc === undefined) continue; // this is caught by other checks
|
||||
const document = d as DocNodeWithJsDoc<DocNode>;
|
||||
switch (document.kind) {
|
||||
case "moduleDoc": {
|
||||
assertModuleDoc(document);
|
||||
break;
|
||||
}
|
||||
case "function": {
|
||||
assertFunctionDocs(document);
|
||||
break;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* This module is browser compatible, but do not rely on good formatting of
|
||||
* values for AssertionError messages in browsers.
|
||||
*
|
||||
* ```ts
|
||||
* ```ts no-eval
|
||||
* import { assert } from "@std/assert/assert";
|
||||
*
|
||||
* assert("I am truthy"); // Doesn't throw
|
||||
|
@ -4,11 +4,12 @@
|
||||
* Tools for creating interactive command line tools.
|
||||
*
|
||||
* ```ts
|
||||
* // $ deno run example.ts --foo --bar=baz ./quux.txt
|
||||
* import { parseArgs } from "@std/cli/parse-args";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* const parsedArgs = parseArgs(Deno.args);
|
||||
* parsedArgs; // { foo: true, bar: "baz", _: ["./quux.txt"] }
|
||||
* // Same as running `deno run example.ts --foo --bar=baz ./quux.txt`
|
||||
* const args = parseArgs(["--foo", "--bar=baz", "./quux.txt"]);
|
||||
* assertEquals(args, { foo: true, bar: "baz", _: ["./quux.txt"] });
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
|
@ -6,19 +6,20 @@
|
||||
*
|
||||
* ```ts
|
||||
* import { BinarySearchTree } from "@std/data-structures";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* const values = [3, 10, 13, 4, 6, 7, 1, 14];
|
||||
* const tree = new BinarySearchTree<number>();
|
||||
* values.forEach((value) => tree.insert(value));
|
||||
*
|
||||
* [...tree]; // [ 1, 3, 4, 6, 7, 10, 13, 14 ]
|
||||
* tree.min(); // 1
|
||||
* tree.max(); // 14
|
||||
* tree.find(42); // null
|
||||
* tree.find(7); // 7
|
||||
* tree.remove(42); // false
|
||||
* tree.remove(7); // true
|
||||
* [...tree]; // [ 1, 3, 4, 6, 10, 13, 14 ]
|
||||
* assertEquals([...tree], [1, 3, 4, 6, 7, 10, 13, 14]);
|
||||
* assertEquals(tree.min(), 1);
|
||||
* assertEquals(tree.max(), 14);
|
||||
* assertEquals(tree.find(42), null);
|
||||
* assertEquals(tree.find(7), 7);
|
||||
* assertEquals(tree.remove(42), false);
|
||||
* assertEquals(tree.remove(7), true);
|
||||
* assertEquals([...tree], [1, 3, 4, 6, 10, 13, 14]);
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
|
@ -69,9 +69,9 @@
|
||||
* - `expect.hasAssertions`
|
||||
* - `expect.addSnapshotSerializer`
|
||||
*
|
||||
* This module is largely inspired by {@link https://github.com/allain/expect | x/expect} module by Allain Lalonde.
|
||||
* This module is largely inspired by
|
||||
* {@link https://github.com/allain/expect | x/expect} module by Allain Lalonde.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { expect } from "@std/expect";
|
||||
*
|
||||
|
@ -11,7 +11,6 @@
|
||||
* This module supports `NO_COLOR` environmental variable disabling any coloring
|
||||
* if `NO_COLOR` is set.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import {
|
||||
* bgBlue,
|
||||
|
@ -4,6 +4,16 @@
|
||||
* {@linkcode sprintf} and {@linkcode printf} for printing formatted strings to
|
||||
* stdout.
|
||||
*
|
||||
* ```ts
|
||||
* import { sprintf } from "@std/fmt/printf";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* assertEquals(sprintf("%d", 9), "9");
|
||||
* assertEquals(sprintf("%o", 9), "11");
|
||||
* assertEquals(sprintf("%f", 4), "4.000000");
|
||||
* assertEquals(sprintf("%.3f", 0.9999), "1.000");
|
||||
* ```
|
||||
*
|
||||
* This implementation is inspired by POSIX and Golang but does not port
|
||||
* implementation code.
|
||||
*
|
||||
|
@ -12,16 +12,17 @@
|
||||
* ### JSON
|
||||
*
|
||||
* ```ts
|
||||
* import { test } from "@std/front-matter/test";
|
||||
* import { extract } from "@std/front-matter/json";
|
||||
* import { test, extractJson } from "@std/front-matter";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* const str = "---json\n{\"and\": \"this\"}\n---\ndeno is awesome";
|
||||
* const result = extract(str);
|
||||
*
|
||||
* test(str); // true
|
||||
* result.frontMatter; // "{\"and\": \"this\"}"
|
||||
* result.body; // "deno is awesome"
|
||||
* result.attrs; // { and: "this" }
|
||||
* assertEquals(test(str), true);
|
||||
* assertEquals(extractJson(str), {
|
||||
* frontMatter: "{\"and\": \"this\"}",
|
||||
* body: "deno is awesome",
|
||||
* attrs: { and: "this" }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* {@linkcode extractJson | extract} and {@linkcode test} support the following
|
||||
@ -44,16 +45,17 @@
|
||||
* ### TOML
|
||||
*
|
||||
* ```ts
|
||||
* import { test } from "@std/front-matter/test";
|
||||
* import { extract } from "@std/front-matter/toml";
|
||||
* import { test, extractToml } from "@std/front-matter";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* const str = "---toml\nmodule = 'front_matter'\n---\ndeno is awesome";
|
||||
* const result = extract(str);
|
||||
*
|
||||
* test(str); // true
|
||||
* result.frontMatter; // "module = 'front_matter'"
|
||||
* result.body; // "deno is awesome"
|
||||
* result.attrs; // { module: "front_matter" }
|
||||
* assertEquals(test(str), true);
|
||||
* assertEquals(extractToml(str), {
|
||||
* frontMatter: "module = 'front_matter'",
|
||||
* body: "deno is awesome",
|
||||
* attrs: { module: "front_matter" }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* {@linkcode extractToml | extract} and {@linkcode test} support the following
|
||||
@ -82,16 +84,17 @@
|
||||
* ### YAML
|
||||
*
|
||||
* ```ts
|
||||
* import { test } from "@std/front-matter/test";
|
||||
* import { extract } from "@std/front-matter/yaml";
|
||||
* import { test, extractYaml } from "@std/front-matter";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* const str = "---yaml\nmodule: front_matter\n---\ndeno is awesome";
|
||||
* const result = extract(str);
|
||||
*
|
||||
* test(str); // true
|
||||
* result.frontMatter; // "module: front_matter"
|
||||
* result.body; // "deno is awesome"
|
||||
* result.attrs; // { module: "front_matter" }
|
||||
* assertEquals(test(str), true);
|
||||
* assertEquals(extractYaml(str), {
|
||||
* frontMatter: "module: front_matter",
|
||||
* body: "deno is awesome",
|
||||
* attrs: { module: "front_matter" }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* {@linkcode extractYaml | extract} and {@linkcode test} support the following
|
||||
|
10
html/mod.ts
10
html/mod.ts
@ -4,6 +4,16 @@
|
||||
/**
|
||||
* Functions for HTML tasks such as escaping or unescaping HTML entities.
|
||||
*
|
||||
* ```ts
|
||||
* import { escape } from "@std/html/entities";
|
||||
*
|
||||
* escape("<>'&AA"); // "<>'&AA"
|
||||
*
|
||||
* // Characters that don't need to be escaped will be left alone,
|
||||
* // even if named HTML entities exist for them.
|
||||
* escape("þð"); // "þð"
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
* For example to integrate the user agent provided in the header `User-Agent`
|
||||
* in an http request would look like this:
|
||||
*
|
||||
* ```ts
|
||||
* ```ts no-eval
|
||||
* import { UserAgent } from "@std/http/user-agent";
|
||||
*
|
||||
* Deno.serve((req) => {
|
||||
|
@ -8,8 +8,7 @@
|
||||
*
|
||||
* This module is browser compatible.
|
||||
*
|
||||
* @example
|
||||
* ```ts Parsing JSONC
|
||||
* ```ts
|
||||
* import { parse } from "@std/jsonc";
|
||||
*
|
||||
* parse('{"foo": "bar", } // comment'); // { foo: "bar" }
|
||||
|
@ -3,10 +3,30 @@
|
||||
// This module is browser compatible.
|
||||
|
||||
/**
|
||||
* The semantic version parser.
|
||||
* The Semantic Version parser.
|
||||
*
|
||||
* Adapted directly from {@link https://github.com/npm/node-semver | semver}.
|
||||
*
|
||||
* ```ts
|
||||
* import {
|
||||
* parse,
|
||||
* parseRange,
|
||||
* greaterThan,
|
||||
* lessThan,
|
||||
* format
|
||||
* } from "@std/semver";
|
||||
*
|
||||
* const semver = parse("1.2.3");
|
||||
* const range = parseRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3");
|
||||
*
|
||||
* const s0 = parse("1.2.3");
|
||||
* const s1 = parse("9.8.7");
|
||||
* greaterThan(s0, s1); // false
|
||||
* lessThan(s0, s1); // true
|
||||
*
|
||||
* format(semver) // "1.2.3"
|
||||
* ```
|
||||
*
|
||||
* ## Versions
|
||||
*
|
||||
* A "version" is described by the `v2.0.0` specification found at
|
||||
@ -242,26 +262,7 @@
|
||||
*
|
||||
* This module is browser compatible.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import {
|
||||
* parse,
|
||||
* parseRange,
|
||||
* greaterThan,
|
||||
* lessThan,
|
||||
* format
|
||||
* } from "@std/semver";
|
||||
*
|
||||
* const semver = parse("1.2.3");
|
||||
* const range = parseRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3");
|
||||
*
|
||||
* const s0 = parse("1.2.3");
|
||||
* const s1 = parse("9.8.7");
|
||||
* greaterThan(s0, s1); // false
|
||||
* lessThan(s0, s1); // true
|
||||
*
|
||||
* format(semver) // "1.2.3"
|
||||
* ```
|
||||
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
@ -5,6 +5,16 @@
|
||||
*
|
||||
* Includes buffering and conversion.
|
||||
*
|
||||
* ```ts
|
||||
* import { toText } from "@std/streams";
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* const stream = ReadableStream.from("Hello, world!");
|
||||
* const text = await toText(stream);
|
||||
*
|
||||
* assertEquals(text, "Hello, world!");
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
|
11
text/mod.ts
11
text/mod.ts
@ -2,7 +2,6 @@
|
||||
// This module is browser compatible.
|
||||
|
||||
/**
|
||||
* @module
|
||||
* Utility functions for working with text.
|
||||
*
|
||||
* There are various functions for manipulating text, such as `toCamelCase`:
|
||||
@ -17,13 +16,17 @@
|
||||
*
|
||||
* ```ts
|
||||
* import { compareSimilarity } from "@std/text/compare-similarity";
|
||||
* const words = ["hi", "hello", "help"];
|
||||
* import { assertEquals } from "@std/assert/assert-equals";
|
||||
*
|
||||
* // words most-similar to "hep" will be at the front
|
||||
* words.sort(compareSimilarity("hep"));
|
||||
* const words = ["hi", "help", "hello"];
|
||||
*
|
||||
* // Words most similar to "hep" will be at the front
|
||||
* assertEquals(words.sort(compareSimilarity("hep")), ["help", "hi", "hello"]);
|
||||
* ```
|
||||
*
|
||||
* This module is browser compatible.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
export * from "./levenshtein_distance.ts";
|
||||
|
@ -90,7 +90,6 @@
|
||||
*
|
||||
* This module is browser compatible.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import {
|
||||
* parse,
|
||||
|
@ -4,6 +4,22 @@
|
||||
* Utilities for interacting with the
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API | WebGPU API}.
|
||||
*
|
||||
* ```ts no-eval
|
||||
* import { createTextureWithData } from "@std/webgpu";
|
||||
*
|
||||
* const adapter = await navigator.gpu.requestAdapter();
|
||||
* const device = await adapter?.requestDevice()!;
|
||||
*
|
||||
* createTextureWithData(device, {
|
||||
* format: "bgra8unorm-srgb",
|
||||
* size: {
|
||||
* width: 3,
|
||||
* height: 2,
|
||||
* },
|
||||
* usage: GPUTextureUsage.COPY_SRC,
|
||||
* }, new Uint8Array([1, 1, 1, 1, 1, 1, 1]));
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user