docs-util: rename docblock-generator to docs-generator (#8331)

* docs-util: rename docblock-generator to docs-generator

* change program name

* fix action
This commit is contained in:
Shahed Nasser
2024-07-29 16:04:33 +03:00
committed by GitHub
parent 7ad4e7b1c9
commit ebaf0eb53a
51 changed files with 40 additions and 19 deletions

View File

@@ -0,0 +1,8 @@
import path from "path"
import { fileURLToPath } from "url"
export default function dirname(fileUrl: string) {
const __filename = fileURLToPath(fileUrl)
return path.dirname(__filename)
}

View File

@@ -0,0 +1,13 @@
import { minimatch } from "minimatch"
export default function (files: string[]): string[] {
return files.filter((file) =>
minimatch(
file,
"**/packages/@(medusa|core/types|medusa-js|medusa-react)/src/**/*.@(ts|tsx|js|jsx)",
{
matchBase: true,
}
)
)
}

View File

@@ -0,0 +1,20 @@
import { stringify } from "yaml"
import { DOCBLOCK_END_LINE, DOCBLOCK_NEW_LINE } from "../constants.js"
import { OpenApiOperation, OpenApiSchema } from "../types/index.js"
/**
* Retrieve the OAS as a formatted string that can be used as a comment.
*
* @param oas - The OAS operation to format.
* @param oasPrefix - The OAS prefix that's used before the OAS operation.
* @returns The formatted OAS comment.
*/
export default function formatOas(
oas: OpenApiOperation | OpenApiSchema,
oasPrefix: string
) {
return `* ${oasPrefix}${DOCBLOCK_NEW_LINE}${stringify(oas).replaceAll(
"\n",
DOCBLOCK_NEW_LINE
)}${DOCBLOCK_END_LINE}`
}

View File

@@ -0,0 +1,15 @@
/**
* Retrieve the pathname of a file without the relative part before `packages/`
*
* @param fileName - The file name/path
* @returns The path without the relative part.
*/
export default function getBasePath(fileName: string) {
let basePath = fileName
const packageIndex = fileName.indexOf("packages/")
if (packageIndex) {
basePath = basePath.substring(packageIndex)
}
return basePath
}

View File

@@ -0,0 +1,23 @@
// Due to some types using Zod in their declaration
// The type name isn't picked properly by typescript
import ts from "typescript"
import isZodObject from "./is-zod-object.js"
// this ensures that the correct type name is used.
export default function getCorrectZodTypeName({
typeReferenceNode,
itemType,
}: {
typeReferenceNode: ts.TypeReferenceNode
itemType: ts.Type
}): string | undefined {
if (!isZodObject(itemType)) {
return
}
return typeReferenceNode.typeArguments?.[0] &&
"typeName" in typeReferenceNode.typeArguments[0]
? (typeReferenceNode.typeArguments?.[0].typeName as ts.Identifier).getText()
: undefined
}

View File

@@ -0,0 +1,15 @@
import path from "path"
import dirname from "./dirname.js"
/**
* Retrieves the monorepo root either from the `MONOREPO_ROOT_PATH` environment
* variable, or inferring it from the path.
*
* @returns {string} The absolute path to the monorepository.
*/
export default function getMonorepoRoot(): string {
return (
process.env.MONOREPO_ROOT_PATH ||
path.join(dirname(import.meta.url), "..", "..", "..", "..", "..", "..")
)
}

View File

@@ -0,0 +1,16 @@
import path from "path"
import getMonorepoRoot from "./get-monorepo-root.js"
/**
* Retrieves the base path to the `oas-output` directory.
*/
export function getOasOutputBasePath() {
return path.join(getMonorepoRoot(), "www", "utils", "generated", "oas-output")
}
/**
* Retrieves the base path to the `dml-output` directory
*/
export function getDmlOutputBasePath() {
return path.join(getMonorepoRoot(), "www", "utils", "generated", "dml-output")
}

View File

@@ -0,0 +1,15 @@
import path from "path"
/**
* Get relative path of multiple file paths to a specified path.
*
* @param {string[]} filePaths - The file paths to retrieve their relative path.
* @param {string} pathPrefix - The path to retrieve paths relative to.
* @returns {string[]} The relative file paths.
*/
export default function getRelativePaths(
filePaths: string[],
pathPrefix: string
): string[] {
return filePaths.map((filePath) => path.resolve(pathPrefix, filePath))
}

View File

@@ -0,0 +1,24 @@
import ts from "typescript"
/**
* Retrieves the symbol of a node.
*
* @param {ts.Node} node - The node to retrieve its symbol.
* @param {ts.TypeChecker} checker - The type checker of the TypeScript program the symbol is in.
* @returns {ts.Symbol | undefined} The symbol if found.
*/
export default function getSymbol(
node: ts.Node,
checker: ts.TypeChecker
): ts.Symbol | undefined {
if (
ts.isVariableStatement(node) &&
node.declarationList.declarations.length
) {
return getSymbol(node.declarationList.declarations[0], checker)
}
return "symbol" in node && node.symbol
? (node.symbol as ts.Symbol)
: undefined
}

View File

@@ -0,0 +1,15 @@
import ts from "typescript"
export default function isZodObject(itemType: ts.Type): boolean {
if (!itemType.symbol?.declarations?.length) {
return false
}
const parent = itemType.symbol.declarations[0].parent
if (!("typeName" in parent)) {
return false
}
return (parent.typeName as ts.Identifier).getText().includes("ZodObject")
}

View File

@@ -0,0 +1,101 @@
import path from "path"
import getMonorepoRoot from "./get-monorepo-root.js"
import ts from "typescript"
import { minimatch } from "minimatch"
import { capitalize } from "utils"
export const kindsCanHaveNamespace = [
ts.SyntaxKind.SourceFile,
ts.SyntaxKind.ClassDeclaration,
ts.SyntaxKind.EnumDeclaration,
ts.SyntaxKind.ModuleDeclaration,
ts.SyntaxKind.InterfaceDeclaration,
ts.SyntaxKind.TypeAliasDeclaration,
ts.SyntaxKind.MethodDeclaration,
ts.SyntaxKind.MethodSignature,
ts.SyntaxKind.FunctionDeclaration,
ts.SyntaxKind.ArrowFunction,
ts.SyntaxKind.VariableStatement,
]
export const pathsHavingCustomNamespace = [
"**/packages/medusa\\-react/src/hooks/**/index.ts",
"**/packages/medusa\\-react/src/@(helpers|contexts)/**/*.@(tsx|ts)",
]
export const CUSTOM_NAMESPACE_TAG = "@customNamespace"
/**
* Get the path used with the {@link CUSTOM_NAMESPACE_TAG}.
*
* @param {ts.Node} node - The node to retrieve its custom namespace path.
* @returns {string} The namespace path.
*/
export function getNamespacePath(node: ts.Node): string {
const packagePathPrefix = `${path.resolve(
getMonorepoRoot(),
"packages/medusa-react/src"
)}/`
const sourceFile = node.getSourceFile()
let hookPath = path
.dirname(sourceFile.fileName)
.replace(packagePathPrefix, "")
const fileName = path.basename(sourceFile.fileName)
if (
!fileName.startsWith("index") &&
!fileName.startsWith("mutations") &&
!fileName.startsWith("queries")
) {
hookPath += `/${fileName.replace(path.extname(fileName), "")}`
}
return hookPath
.split("/")
.map((pathItem, index) => {
if (index === 0) {
pathItem = pathItem
.replace("contexts", "providers")
.replace("helpers", "utilities")
}
return pathItem
.split("-")
.map((item) => capitalize(item))
.join(" ")
})
.join(".")
}
/**
* Retrieves the full tag of the custom namespace with its value.
*
* @param {ts.Node} node - The node to retrieve its custom namespace path.
* @returns {string} The custom namespace tag and value.
*/
export function getCustomNamespaceTag(node: ts.Node): string {
return `${CUSTOM_NAMESPACE_TAG} ${getNamespacePath(node)}`
}
/**
* Checks whether a node should have a custom namespace path.
*
* @param {ts.Node} node - The node to check.
* @returns {boolean} Whether the node should have a custom namespace.
*/
export function shouldHaveCustomNamespace(node: ts.Node): boolean {
if (!kindsCanHaveNamespace.includes(node.kind)) {
return false
}
const fileName = node.getSourceFile().fileName
return pathsHavingCustomNamespace.some((pattern) =>
minimatch(fileName, pattern, {
matchBase: true,
})
)
}

View File

@@ -0,0 +1,42 @@
import { parse } from "yaml"
import { OpenApiOperation } from "../types/index.js"
import { DOCBLOCK_LINE_ASTRIX } from "../constants.js"
export type ExistingOas = {
oas: OpenApiOperation
oasPrefix: string
}
export default function parseOas(content: string): ExistingOas | undefined {
content = content
.replace(`/**\n`, "")
.replaceAll(DOCBLOCK_LINE_ASTRIX, "")
.replaceAll("*/", "")
.trim()
if (!content.startsWith("@oas")) {
// the file is of an invalid format.
return
}
// extract oas prefix line
const splitNodeComments = content.split("\n")
const oasPrefix = content.split("\n")[0]
content = splitNodeComments.slice(1).join("\n")
let oas: OpenApiOperation | undefined
try {
oas = parse(content) as OpenApiOperation
} catch (e) {
// couldn't parse the OAS, so consider it
// not existent
}
return oas
? {
oas,
oasPrefix,
}
: undefined
}

View File

@@ -0,0 +1,4 @@
import util from "node:util"
import { exec } from "child_process"
export default util.promisify(exec)

View File

@@ -0,0 +1,15 @@
/**
* Remove parts of the name such as DTO, Filterable, etc...
*
* @param {string} str - The name to format.
* @returns {string} The normalized name.
*/
export function normalizeName(str: string): string {
return str
.replace(/^(create|update|delete|upsert)/i, "")
.replace(/DTO$/, "")
.replace(/^Filterable/, "")
.replace(/Props$/, "")
.replace(/^I([A-Z])/, "$1")
.replace(/ModuleService$/, "")
}

View File

@@ -0,0 +1,9 @@
/**
* Retrieves the stringified JSON of a variable formatted.
*
* @param item The item to stringify
* @returns The formatted JSON string
*/
export default function toJsonFormatted(item: unknown): string {
return JSON.stringify(item, undefined, "\t")
}