docs-util: add configuration to generate js-sdk reference (#9630)

This commit is contained in:
Shahed Nasser
2024-10-17 19:32:21 +03:00
committed by GitHub
parent ab113cdc38
commit b07dd33a57
14 changed files with 339 additions and 31 deletions

View File

@@ -0,0 +1,11 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"extends": [
"../../../../packages/core/js-sdk/tsconfig.json"
],
"include": ["../../../../packages/core/js-sdk/src"],
"exclude": [
"../../../../packages/core/js-sdk/dist",
"../../../../packages/core/js-sdk/node_modules"
]
}

View File

@@ -12,7 +12,7 @@ export const baseOptions: Partial<TypeDocOptions> = {
"www/packages/eslint-config-docs/content.js"
),
pluginsResolvePath: path.join(rootPathPrefix, "www"),
exclude: [path.join(rootPathPrefix, "node_modules/**")],
exclude: ["**/node_modules/**"],
excludeInternal: true,
excludeExternals: true,
excludeReferences: true,

View File

@@ -49,6 +49,16 @@ const customOptions: Record<string, Partial<TypeDocOptions>> = {
name: "fulfillment-provider",
parentIgnore: true,
}),
"js-sdk": getOptions({
entryPointPath: [
"packages/core/js-sdk/src/admin/index.ts",
"packages/core/js-sdk/src/auth/index.ts",
"packages/core/js-sdk/src/store/index.ts",
],
tsConfigName: "js-sdk.json",
name: "js-sdk",
enableInternalResolve: true,
}),
"helper-steps": getOptions({
entryPointPath: "packages/core/core-flows/src/common/index.ts",
tsConfigName: "core-flows.json",
@@ -62,12 +72,13 @@ const customOptions: Record<string, Partial<TypeDocOptions>> = {
],
}),
"medusa-config": getOptions({
entryPointPath: "packages/framework/src/config/types.ts",
entryPointPath: "packages/core/framework/src/config/types.ts",
tsConfigName: "framework.json",
name: "medusa-config",
exclude: [...(baseOptions.exclude || []), "**/dist/**"],
}),
medusa: getOptions({
entryPointPath: "packages/medusa/src/index.js",
entryPointPath: "packages/medusa/src/index.ts",
tsConfigName: "medusa.json",
name: "medusa",
jsonFileName: "0-medusa",
@@ -140,10 +151,13 @@ const customOptions: Record<string, Partial<TypeDocOptions>> = {
enableInternalResolve: true,
exclude: [
...(baseOptions.exclude || []),
"**/dist/**",
"**/api-key/**",
"**/auth/**",
"**/bundles/**",
"**/common/**",
"**/dal/**/**",
"**/decorators/**",
"**/dml/**",
"**/defaults/**",
"**/**provider.ts",
"**/event-bus/**",
@@ -151,10 +165,10 @@ const customOptions: Record<string, Partial<TypeDocOptions>> = {
"**/feature-flags/**",
"**/modules-sdk/**",
"**/orchestration/**",
"**/pg/**",
"**/pricing/builders.ts",
"**/search/**",
"**/totals/**",
"**/dml/**",
],
}),
workflows: getOptions({

View File

@@ -12,6 +12,7 @@ import taxProviderOptions from "./tax-provider.js"
import workflowsOptions from "./workflows.js"
import dmlOptions from "./dml.js"
import coreFlowsOptions from "./core-flows.js"
import jsSdkOptions from "./js-sdk.js"
const mergerCustomOptions: FormattingOptionsType = {
...authProviderOptions,
@@ -20,6 +21,7 @@ const mergerCustomOptions: FormattingOptionsType = {
...fileOptions,
...fulfillmentProviderOptions,
...helperStepsOptions,
...jsSdkOptions,
...medusaConfigOptions,
...medusaOptions,
...notificationOptions,

View File

@@ -0,0 +1,88 @@
import { FormattingOptionsType } from "types"
import baseSectionsOptions from "../base-section-options.js"
const jsSdkOptions: FormattingOptionsType = {
"^js_sdk": {
expandMembers: true,
expandProperties: true,
reflectionGroups: {
Constructors: false,
},
sections: {
...baseSectionsOptions,
member_declaration_title: false,
member_declaration_children: true,
},
},
"^js_sdk/store/classes/.*Store": {
frontmatterData: {
slug: "/references/js-sdk/store",
},
reflectionDescription:
"The `sdk.store` class provides methods to send requests to Medusa's Store API routes.",
reflectionTitle: {
fullReplacement: "JS SDK Store Reference",
},
},
"^js_sdk/store/Store/properties/": {
frontmatterData: {
slug: "/references/js-sdk/admin/{{alias}}",
sidebar_label: "{{alias}}",
},
reflectionTitle: {
kind: false,
typeParameters: false,
suffix: "- JS SDK Store Reference",
},
reflectionDescription:
"This documentation provides a reference to the `sdk.store.{{alias}}` set of methods used to send requests to Medusa's Store API routes.",
},
"^js_sdk/store/classes/.*Admin": {
frontmatterData: {
slug: "/references/js-sdk/admin",
},
reflectionDescription:
"The `sdk.admin` class provides methods to send requests to Medusa's Admin API routes.",
reflectionTitle: {
fullReplacement: "JS SDK Admin Reference",
},
},
"^js_sdk/admin/Admin/properties/": {
frontmatterData: {
slug: "/references/js-sdk/admin/{{alias}}",
sidebar_label: "{{alias}}",
},
reflectionTitle: {
kind: false,
typeParameters: false,
suffix: "- JS SDK Admin Reference",
},
reflectionDescription:
"This documentation provides a reference to the `sdk.admin.{{alias}}` set of methods used to send requests to Medusa's Admin API routes.",
},
"^js_sdk/store/classes/.*Auth": {
frontmatterData: {
slug: "/references/js-sdk/auth",
},
reflectionDescription:
"The `sdk.auth` class provides methods to send requests to manage a user or customer's authentication",
reflectionTitle: {
fullReplacement: "JS SDK Auth Reference",
},
},
"^js_sdk/auth/Auth/methods/": {
frontmatterData: {
slug: "/references/js-sdk/auth/{{alias}}",
sidebar_label: "{{alias}}",
},
reflectionTitle: {
kind: false,
typeParameters: false,
suffix: "- JS SDK Auth Reference",
},
reflectionDescription:
"This documentation provides a reference to the `sdk.auth.{{alias}}` method used to send requests to Medusa's Authentication API routes. It can be used for admin users, customers, or custom actor types.",
},
}
export default jsSdkOptions

View File

@@ -40,6 +40,7 @@ const mergerOptions: Partial<TypeDocOptions> = {
"helper-steps",
"workflows",
],
allPropertyReflectionsHaveOwnDocument: ["js-sdk"],
allReflectionsHaveOwnDocumentInNamespace: [
...getNamespaceNames(getCoreFlowNamespaces()),
],

View File

@@ -27,6 +27,7 @@ const allReferences = [
"file",
"fulfillment-provider",
"helper-steps",
"js-sdk",
"medusa-config",
"medusa",
"modules-sdk",

View File

@@ -40,6 +40,13 @@ export function load(app: Application) {
defaultValue: [],
})
app.options.addDeclaration({
help: "[Markdown Plugin] Specify module names where property reflections are outputted into seperate files.",
name: "allPropertyReflectionsHaveOwnDocument",
type: ParameterType.Array,
defaultValue: [],
})
app.options.addDeclaration({
help: "[Markdown Plugin] Specify namespace names where all reflections are outputted into seperate files.",
name: "allReflectionsHaveOwnDocumentInNamespace",

View File

@@ -56,24 +56,10 @@
{{#if type.declaration.signatures}}
{{#if type.declaration.children}}
{{{titleLevel}}} Call signature
{{else}}
{{{titleLevel}}} Type declaration
{{/if}}
{{#each type.declaration.signatures}}
{{incrementCurrentTitleLevel}}
{{> member.signature-wrapper showSources=false parent=../type.declaration }}
{{decrementCurrentTitleLevel}}
{{/each}}
{{/if}}
@@ -84,11 +70,23 @@
{{#if type.declaration.children}}
{{#with type.declaration}}
{{#unless (getFormattingOption "expandMembers")}}
{{{titleLevel}}} Properties
{{/with}}
{{incrementCurrentTitleLevel}}
{{/unless}}
{{#if (shouldExpandProperties "Properties")}}
{{#each type.declaration.children}}
{{> member }}
{{/each}}
{{else}}
{{#with type.declaration.children}}
@@ -98,6 +96,14 @@
{{/if}}
{{#unless (getFormattingOption "expandMembers")}}
{{decrementCurrentTitleLevel}}
{{/unless}}
{{/if}}
{{/if}}
{{/if}}

View File

@@ -30,6 +30,7 @@ import { Mapping } from "./types"
export class MarkdownTheme extends Theme {
allReflectionsHaveOwnDocument!: string[]
allPropertyReflectionsHaveOwnDocument!: string[]
allReflectionsHaveOwnDocumentInNamespace: string[]
entryDocument: string
entryPoints!: string[]
@@ -65,6 +66,9 @@ export class MarkdownTheme extends Theme {
// prettier-ignore
this.allReflectionsHaveOwnDocument = this.getOption("allReflectionsHaveOwnDocument") as string[]
this.allPropertyReflectionsHaveOwnDocument = this.getOption(
"allPropertyReflectionsHaveOwnDocument"
) as string[]
this.allReflectionsHaveOwnDocumentInNamespace = this.getOption(
"allReflectionsHaveOwnDocumentInNamespace"
) as string[]
@@ -334,7 +338,10 @@ export class MarkdownTheme extends Theme {
return parents
}
getAllReflectionsHaveOwnDocument(reflection: DeclarationReflection): boolean {
getAllReflectionsHaveOwnDocument(
reflection: DeclarationReflection,
checkProperties?: boolean
): boolean {
const moduleParents = this.getParentsOfKind(
reflection,
ReflectionKind.Module
@@ -344,6 +351,12 @@ export class MarkdownTheme extends Theme {
ReflectionKind.Namespace
)
if (checkProperties) {
return moduleParents.some((parent) =>
this.allPropertyReflectionsHaveOwnDocument.includes(parent.name)
)
}
return (
moduleParents.some((parent) =>
this.allReflectionsHaveOwnDocument.includes(parent.name)
@@ -458,6 +471,20 @@ export class MarkdownTheme extends Theme {
},
]
: []),
...(this.getAllReflectionsHaveOwnDocument(reflection, true)
? [
{
kind: [ReflectionKind.Property],
modifiers: {
has: [],
not: [],
},
isLeaf: true,
directory: path.join(directoryPrefix || "", "properties"),
template: this.getReflectionMemberTemplate(),
},
]
: []),
]
}

View File

@@ -92,7 +92,8 @@ class WorkflowsPlugin {
const workflowId = this.helper.getStepOrWorkflowId(
initializer,
context.project
context.project,
"workflow"
)
if (!workflowId) {
@@ -270,6 +271,7 @@ class WorkflowsPlugin {
stepId = this.helper.getStepOrWorkflowId(
originalInitializer,
context.project,
"step",
true
)
stepType = this.helper.getStepType(originalInitializer)

View File

@@ -3,8 +3,9 @@ import {
ParameterReflection,
ProjectReflection,
} from "typedoc"
import ts, { isStringLiteral } from "typescript"
import ts from "typescript"
import { StepModifier, StepType } from "../types"
import { capitalize } from "utils"
/**
* A class of helper methods.
@@ -84,13 +85,22 @@ export default class Helper {
* @returns The ID of the step or workflow.
*/
getStepOrWorkflowId(
initializer: ts.CallExpression,
initializer: ts.CallExpression | ts.ArrowFunction,
project: ProjectReflection,
type: "workflow" | "step",
checkWorkflowStep = false
): string | undefined {
const idArg = initializer.arguments[0]
const callInitializer = ts.isCallExpression(initializer)
? initializer
: this.getCallExpressionFromBody(initializer.body)
if (!callInitializer) {
throw new Error(
`Couldn't find initializer of a step or workflow: ${initializer.getText()}`
)
}
const idArg = callInitializer.arguments[0]
const isWorkflowStep =
checkWorkflowStep && this.getStepType(initializer) === "workflowStep"
checkWorkflowStep && this.getStepType(callInitializer) === "workflowStep"
const idArgValue = this.normalizeName(idArg.getText())
let stepId: string | undefined
@@ -106,15 +116,58 @@ export default class Helper {
? nameValue
: this.getValueFromReflection(nameValue, project)
}
} else if (!isStringLiteral(idArg)) {
} else if (!ts.isStringLiteral(idArg)) {
stepId = this.getValueFromReflection(idArgValue, project)
} else {
stepId = idArgValue
}
if (!stepId && ts.isArrowFunction(initializer)) {
stepId = this._getStepOrWorkflowIdFromArrowFunction(initializer, type)
}
return isWorkflowStep ? `${stepId}-as-step` : stepId
}
private _getStepOrWorkflowIdFromArrowFunction(
initializer: ts.ArrowFunction,
type: "workflow" | "step"
) {
// for arrow functions, the inner workflow / step isn't exported
// so we have to rely on a hacky way of retrieving the ID from the source file
const sourceFile = initializer.getSourceFile()
const localMap: Map<string, ts.Symbol> =
"locals" in sourceFile
? (sourceFile.locals as Map<string, ts.Symbol>)
: new Map()
if (!localMap.size) {
throw new Error(`Couldn't find ID of ${type}: ${initializer.getText()}`)
}
let id = ""
const capitalizedType = capitalize(type)
localMap.forEach((value, key) => {
if (
!key.endsWith(`${capitalizedType}Id`) ||
id.length ||
!value.declarations?.length ||
!ts.isVariableDeclaration(value.declarations[0])
) {
return
}
id = value.declarations[0].initializer?.getText() || ""
})
if (!id.length) {
throw new Error(`Couldn't find ID of ${type}: ${initializer.getText()}`)
}
return this.normalizeName(id)
}
private getValueFromReflection(
refName: string,
project: ProjectReflection
@@ -139,8 +192,9 @@ export default class Helper {
* @param initializer - The initializer of the step.
* @returns The step's type.
*/
getStepType(initializer: ts.CallExpression): StepType {
switch (initializer.expression.getText()) {
getStepType(initializer: ts.CallExpression | ts.ArrowFunction): StepType {
const stepText = this._getStepText(initializer)
switch (stepText) {
case "createWorkflow":
return "workflowStep"
case "createHook":
@@ -152,6 +206,57 @@ export default class Helper {
}
}
private _getStepText(
initializer: ts.CallExpression | ts.ArrowFunction
): string {
if (ts.isCallExpression(initializer)) {
return initializer.expression.getText()
}
const callExpression = this.getCallExpressionFromBody(initializer.body)
if (
callExpression &&
(!("symbol" in callExpression) || !callExpression.symbol)
) {
// for arrow functions, the inner workflow / step isn't exported
// so we have to rely on a hacky way of retrieving the text from the source file
const sourceFile = initializer.getSourceFile()
const localMap: Map<string, ts.Symbol> =
"locals" in sourceFile
? (sourceFile.locals as Map<string, ts.Symbol>)
: new Map()
let text = ""
const fnName = callExpression.expression.getText()
localMap.forEach((value, key) => {
if (text.length) {
return
}
if (
key === fnName &&
value.declarations?.length &&
"initializer" in value.declarations[0] &&
ts.isCallExpression(value.declarations[0].initializer as ts.Node)
) {
text = this._getStepText(
value.declarations[0].initializer as ts.CallExpression
)
}
})
return text
} else if (callExpression?.symbol) {
return (
(callExpression.symbol as ts.Symbol).declarations?.[0].getText() || ""
)
}
return ""
}
/**
* Get the modifier to use based on the step's type.
*
@@ -193,4 +298,39 @@ export default class Helper {
return str
}
getCallExpressionFromBody(
body: ts.ConciseBody
): ts.CallExpression | undefined {
let callExpression: ts.CallExpression | undefined
const checkChildren = (child: ts.Node) => {
if (callExpression) {
return
} else if (ts.isCallExpression(child)) {
callExpression = child
return
}
if ("expression" in child) {
checkChildren(child.expression as ts.Node)
}
}
body.forEachChild(checkChildren)
return callExpression
}
getIdentifierExpression(node: ts.Node): ts.Identifier | undefined {
if (ts.isIdentifier(node)) {
return node
}
if ("expression" in node) {
return this.getIdentifierExpression(node.expression as ts.Node)
}
return
}
}

View File

@@ -140,6 +140,10 @@ export declare module "typedoc" {
* [Markdown Plugin] Specify module names where all reflections are outputted into seperate files.
*/
allReflectionsHaveOwnDocument: string[]
/**
* [Markdown Plugin] Specify module names where property reflections are outputted into seperate files.
*/
allPropertyReflectionsHaveOwnDocument: string[]
/**
* [Markdown Plugin] Separator used to format filenames.
* @defaultValue "."

View File

@@ -170,7 +170,12 @@ const REJECTED_CHILDREN_NAMES = ["__type"]
function filterChildren(children: DeclarationReflection[]) {
return children.filter(
(child) => !REJECTED_CHILDREN_NAMES.includes(child.name)
(child) =>
!REJECTED_CHILDREN_NAMES.includes(child.name) &&
!child.comment?.modifierTags.has("@ignore") &&
!child.signatures?.some(
(signature) => signature.comment?.modifierTags.has("@ignore")
)
)
}