docs-util: created docblock-generator tool (#6096)

This commit is contained in:
Shahed Nasser
2024-01-24 12:13:40 +02:00
committed by GitHub
parent d68089b2aa
commit f29948a6a8
37 changed files with 2684 additions and 115 deletions

View File

@@ -0,0 +1,8 @@
import path from "path"
import { fileURLToPath } from "url"
export default function dirname() {
const __filename = fileURLToPath(import.meta.url)
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|types|medusa-js|medusa-react)/src/**/*.@(ts|tsx|js|jsx)",
{
matchBase: true,
}
)
)
}

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() {
return (
process.env.MONOREPO_ROOT_PATH ||
path.join(dirname(), "..", "..", "..", "..", "..")
)
}

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,101 @@
import path from "path"
import getMonorepoRoot from "./get-monorepo-root.js"
import ts from "typescript"
import { minimatch } from "minimatch"
import { capitalize } from "./str-formatting.js"
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,16 @@
import ts from "typescript"
/**
* Checks whether a node has comments.
*
* @param {ts.Node} node - The node to check.
* @returns {boolean} Whether the node has comments.
*/
export default function nodeHasComments(node: ts.Node): boolean {
return (
ts.getLeadingCommentRanges(
node.getSourceFile().getFullText(),
node.getFullStart()
) !== 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,38 @@
export function capitalize(str: string): string {
return `${str.charAt(0).toUpperCase()}${str.substring(1).toLowerCase()}`
}
export function camelToWords(str: string): string {
return str
.replaceAll(/([A-Z])/g, " $1")
.trim()
.toLowerCase()
}
export function camelToTitle(str: string): string {
return str
.replaceAll(/([A-Z])/g, " $1")
.split(" ")
.map((word) => capitalize(word))
.join(" ")
.trim()
.toLowerCase()
}
export function snakeToWords(str: string): string {
return str.replaceAll("_", " ").toLowerCase()
}
/**
* 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)/i, "")
.replace(/DTO$/, "")
.replace(/^Filterable/, "")
.replace(/Props$/, "")
}