From 0b3b34e21709c6ffc01daf0e1485300a078e1162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20Ve=C4=8Derek?= Date: Mon, 25 Nov 2024 12:00:34 +0100 Subject: [PATCH] fix: typecheck examples deeply nested within namespaces (#93) (#94) --- .changeset/poor-plants-look.md | 5 +++ schema.json | 42 ++++++++--------------- src/Core.ts | 63 ++++++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 .changeset/poor-plants-look.md diff --git a/.changeset/poor-plants-look.md b/.changeset/poor-plants-look.md new file mode 100644 index 0000000..8f52479 --- /dev/null +++ b/.changeset/poor-plants-look.md @@ -0,0 +1,5 @@ +--- +"@effect/docgen": patch +--- + +Typecheck examples deeply nested within namespaces diff --git a/schema.json b/schema.json index d842d4a..e49e438 100644 --- a/schema.json +++ b/schema.json @@ -7,63 +7,51 @@ "required": [], "properties": { "$schema": { - "type": "string", - "description": "a string", - "title": "string" + "type": "string" }, "projectHomepage": { "type": "string", - "description": "Will link to the project homepage from the Auxiliary Links of the generated documentation.", - "title": "string" + "description": "Will link to the project homepage from the Auxiliary Links of the generated documentation." }, "srcDir": { "type": "string", "description": "The directory in which docgen will search for TypeScript files to parse.", - "title": "string", "default": "src" }, "outDir": { "type": "string", "description": "The directory to which docgen will generate its output markdown documents.", - "title": "string", "default": "docs" }, "theme": { "type": "string", "description": "The theme that docgen will specify should be used for GitHub Docs in the generated _config.yml file.", - "title": "string", "default": "mikearnaldi/just-the-docs" }, "enableSearch": { "type": "boolean", "description": "Whether or not search should be enabled for GitHub Docs in the generated _config.yml file.", - "title": "boolean", "default": true }, "enforceDescriptions": { "type": "boolean", "description": "Whether or not descriptions for each module export should be required.", - "title": "boolean", "default": false }, "enforceExamples": { "type": "boolean", "description": "Whether or not @example tags for each module export should be required. (Note: examples will not be enforced in module documentation)", - "title": "boolean", "default": false }, "enforceVersion": { "type": "boolean", "description": "Whether or not @since tags for each module export should be required.", - "title": "boolean", "default": true }, "exclude": { "type": "array", "items": { - "type": "string", - "description": "a string", - "title": "string" + "type": "string" }, "description": "An array of glob strings specifying files that should be excluded from the documentation.", "default": [] @@ -71,17 +59,17 @@ "parseCompilerOptions": { "anyOf": [ { - "type": "string", - "description": "a string", - "title": "string" + "type": "string" }, { "type": "object", "required": [], "properties": {}, - "additionalProperties": { - "$id": "/schemas/unknown", - "title": "unknown" + "patternProperties": { + "": { + "$id": "/schemas/unknown", + "title": "unknown" + } } } ], @@ -91,17 +79,17 @@ "examplesCompilerOptions": { "anyOf": [ { - "type": "string", - "description": "a string", - "title": "string" + "type": "string" }, { "type": "object", "required": [], "properties": {}, - "additionalProperties": { - "$id": "/schemas/unknown", - "title": "unknown" + "patternProperties": { + "": { + "$id": "/schemas/unknown", + "title": "unknown" + } } } ], diff --git a/src/Core.ts b/src/Core.ts index 568862c..4f7a6c8 100644 --- a/src/Core.ts +++ b/src/Core.ts @@ -8,6 +8,7 @@ import * as CommandExecutor from "@effect/platform/CommandExecutor" import * as FileSystem from "@effect/platform/FileSystem" import * as Path from "@effect/platform/Path" import chalk from "chalk" +import { pipe } from "effect" import * as Array from "effect/Array" import * as Chunk from "effect/Chunk" import * as Effect from "effect/Effect" @@ -130,6 +131,32 @@ const typeCheckAndRunExamples = (modules: ReadonlyArray) => } }) +/** + * Joins an array of strings with a "-" after dropping all empty strings. + */ +const filterJoin = (self: Array) => + pipe( + self, + Array.filter(String.isNonEmpty), + Array.join("-") + ) + +/** + * Extracts deeply nested namespaces with their corresponding namespace prefix + * from a given namespace. + */ +const extractPrefixedNestedNamespaces = ( + doc: Domain.Namespace, + prefix: string +): ReadonlyArray<[string, Domain.Namespace]> => { + const newPrefix = String.isEmpty(prefix) ? doc.name : `${prefix}-${doc.name}` + const namespaces = Array.flatMap( + doc.namespaces, + (namespace) => extractPrefixedNestedNamespaces(namespace, newPrefix) + ) + return Array.prepend(namespaces, [prefix, doc]) +} + /** * Generates example files for the given modules. */ @@ -155,6 +182,9 @@ const getExampleFiles = (modules: ReadonlyArray) => ) ) + const allPrefixedNamespaces = Array.flatMap(module.namespaces, (namespace) => + extractPrefixedNestedNamespaces(namespace, "")) + const moduleExamples = getFiles("module")(module) const methodsExamples = Array.flatMap(module.classes, (c) => Array.flatten([ @@ -167,13 +197,33 @@ const getExampleFiles = (modules: ReadonlyArray) => getFiles(`${c.name}-staticmethod`) ) ])) + const allPrefixedInterfaces = [ + ...module.interfaces.map((iface) => + ["" as string, iface] as const + ), + ...Array.flatMap(allPrefixedNamespaces, ([prefix, namespace]) => + namespace.interfaces.map((iface) => + [filterJoin([prefix, namespace.name]), iface] as const + )) + ] const interfacesExamples = Array.flatMap( - module.interfaces, - getFiles("interface") + allPrefixedInterfaces, + ([ns, doc]) => + getFiles(filterJoin(["interface", ns]))(doc) ) + const allPrefixedTypeAliases = [ + ...module.typeAliases.map((typeAlias) => + ["" as string, typeAlias] as const + ), + ...Array.flatMap(allPrefixedNamespaces, ([prefix, namespace]) => + namespace.typeAliases.map((typeAlias) => + [filterJoin([prefix, namespace.name]), typeAlias] as const + )) + ] const typeAliasesExamples = Array.flatMap( - module.typeAliases, - getFiles("typealias") + allPrefixedTypeAliases, + ([ns, doc]) => + getFiles(filterJoin(["typealias", ns]))(doc) ) const constantsExamples = Array.flatMap( module.constants, @@ -184,8 +234,9 @@ const getExampleFiles = (modules: ReadonlyArray) => getFiles("function") ) const namespacesExamples = Array.flatMap( - module.namespaces, - getFiles("namespace") + allPrefixedNamespaces, + ([ns, doc]) => + getFiles(filterJoin(["namespace", ns]))(doc) ) return Array.flatten([