docs-util: infer resolved resources in workflow + steps (#10637)

This commit is contained in:
Shahed Nasser
2024-12-17 19:03:00 +02:00
committed by GitHub
parent 0a40b69276
commit ee62083c52
7 changed files with 331 additions and 10 deletions
@@ -0,0 +1,136 @@
import ts from "typescript"
import { getUniqueStrArray } from "./str-utils"
import { camelToWords } from "./str-formatting"
const RESOLVE_EXPRESSIONS = [`container.resolve`, `req.scope.resolve`]
export const getResolvedResources = (
functionExpression: ts.ArrowFunction | ts.FunctionDeclaration
): string[] => {
const resources: string[] = []
if (!functionExpression.body) {
return resources
}
const body = ts.isBlock(functionExpression.body)
? functionExpression.body
: getBlockFromNode(functionExpression.body)
if (!body) {
return resources
}
body.statements.forEach((statement) => {
if (!ts.isVariableStatement(statement)) {
return
}
statement.declarationList.declarations.forEach((declaration) => {
if (
!declaration.initializer ||
!ts.isCallExpression(declaration.initializer) ||
!declaration.initializer.arguments.length ||
!("name" in declaration.initializer.arguments[0])
) {
return
}
const initializerText = declaration.initializer.getText()
const isContainerExpression = RESOLVE_EXPRESSIONS.some((exp) =>
initializerText.startsWith(exp)
)
if (!isContainerExpression) {
return
}
const resourceName = normalizeResolvedResourceName(
declaration.initializer.arguments[0]
)
if (!resourceName.length) {
return
}
resources.push(resourceName)
})
})
return resources
}
export const getResolvedResourcesOfStep = (
expression: ts.CallExpression,
stepId?: string
): string[] => {
if (
!expression.arguments ||
expression.arguments.length < 2 ||
(!ts.isArrowFunction(expression.arguments[1]) &&
!ts.isFunctionDeclaration(expression.arguments[1]))
) {
return stepId ? getResolvedResourcesByStepId(stepId) : []
}
const stepFunction: ts.ArrowFunction | ts.FunctionDeclaration =
expression.arguments[1]
let resources = getResolvedResources(stepFunction)
if (
expression.arguments.length === 3 &&
(ts.isArrowFunction(expression.arguments[2]) ||
ts.isFunctionDeclaration(expression.arguments[2]))
) {
// get resolved resources of compensation function
resources.push(...getResolvedResources(expression.arguments[2]))
// make resources unique
resources = getUniqueStrArray(resources)
}
if (!resources.length && stepId) {
return getResolvedResourcesByStepId(stepId)
}
return resources
}
const normalizeResolvedResourceName = (expression: ts.Expression): string => {
let name = ""
switch (true) {
case ts.isPropertyAccessExpression(expression):
name = expression.name.getText()
break
case ts.isStringLiteral(expression):
name = camelToWords(expression.getText())
}
return name.toLowerCase().replaceAll("_", " ")
}
const getBlockFromNode = (node: ts.Node): ts.Block | undefined => {
if ("body" in node) {
if (ts.isBlock(node.body as ts.Node)) {
return node.body as ts.Block
}
return getBlockFromNode(node.body as ts.Node)
}
if ("expression" in node) {
return getBlockFromNode(node.expression as ts.Node)
}
return undefined
}
/**
* Some steps like useQueryGraphStep are not possible
* to detect due to their implementation. For those,
* we have static resolutions
*/
const STEPS_RESOLVED_RESOURCES: Record<string, string[]> = {
"use-query-graph-step": ["query"],
}
export const getResolvedResourcesByStepId = (stepId: string): string[] => {
return STEPS_RESOLVED_RESOURCES[stepId] || []
}
+1
View File
@@ -1,6 +1,7 @@
export * from "./dml-utils"
export * from "./get-type-children"
export * from "./get-project-child"
export * from "./get-resolved-resources"
export * from "./get-type-str"
export * from "./hooks-util"
export * from "./step-utils"
@@ -21,3 +21,7 @@ export function stripLineBreaks(str: string) {
.trim()
: ""
}
export function getUniqueStrArray(str: string[]): string[] {
return Array.from(new Set(str))
}
+48 -3
View File
@@ -1,11 +1,17 @@
import { CommentTag, DeclarationReflection, Reflection } from "typedoc"
import { Comment, CommentTag, DeclarationReflection, Reflection } from "typedoc"
import { getUniqueStrArray } from "./str-utils"
export const getTagsAsArray = (tag: CommentTag): string[] => {
return tag.content
export const getTagsAsArray = (
tag: CommentTag,
makeUnique = true
): string[] => {
const tags = tag.content
.map((content) => content.text)
.join("")
.split(",")
.map((value) => value.trim())
return makeUnique ? getUniqueStrArray(tags) : tags
}
export const getTagComments = (reflection: Reflection): CommentTag[] => {
@@ -23,3 +29,42 @@ export const getTagComments = (reflection: Reflection): CommentTag[] => {
return tagComments
}
export const getTagsAsValue = (tags: string[]): string => {
return tags.join(",")
}
export const addTagsToReflection = (
reflection: Reflection,
tags: string[]
): string[] => {
let tempTags = [...tags]
// check if reflection has an existing tag
const existingTag = reflection.comment?.blockTags.find(
(tag) => tag.tag === `@tags`
)
if (existingTag) {
tempTags.push(...getTagsAsArray(existingTag))
}
if (!tags.length) {
return tempTags
}
// make tags unique
tempTags = getUniqueStrArray(tempTags)
if (!reflection.comment) {
reflection.comment = new Comment()
}
reflection.comment.blockTags.push(
new CommentTag(`@tags`, [
{
kind: "text",
text: getTagsAsValue(tempTags),
},
])
)
return tempTags
}