diff --git a/packages/core/types/src/dml/index.ts b/packages/core/types/src/dml/index.ts index 66bfc24652..6236b9dd25 100644 --- a/packages/core/types/src/dml/index.ts +++ b/packages/core/types/src/dml/index.ts @@ -65,6 +65,11 @@ export type PropertyType = { * Options accepted by all the relationships */ export type RelationshipOptions = { + /** + * The name of the relationship as defined + * in the other data model. This is only required + * by the `belongsTo` relationship method. + */ mappedBy?: string } & Record @@ -152,6 +157,10 @@ export type ExtractEntityRelations< * relationship. */ export type EntityCascades = { + /** + * The related models to delete when a record of this data model + * is deleted. + */ delete?: Relationships } @@ -186,9 +195,23 @@ export type EntityIndex< TSchema extends DMLSchema = DMLSchema, TWhere = string > = { + /** + * The name of the index. If not provided, + * Medusa generates the name. + */ name?: string + /** + * When enabled, a unique index is created on the specified + * properties. + */ unique?: boolean + /** + * The list of properties to create the index on. + */ on: InferIndexableProperties>[] + /** + * Conditions to restrict which records are indexed. + */ where?: TWhere } diff --git a/packages/core/utils/src/dml/entity-builder.ts b/packages/core/utils/src/dml/entity-builder.ts index 2b9a23088d..9d84a9fb2f 100644 --- a/packages/core/utils/src/dml/entity-builder.ts +++ b/packages/core/utils/src/dml/entity-builder.ts @@ -22,7 +22,43 @@ import { ManyToMany } from "./relations/many-to-many" */ const IMPLICIT_PROPERTIES = ["created_at", "updated_at", "deleted_at"] -type DefineOptions = string | { name?: string; tableName: string } +export type DefineOptions = string | { + /** + * The data model's name. + */ + name?: string + /** + * The name of the data model's table in the database. + */ + tableName: string +} + +export type ManyToManyOptions = RelationshipOptions & +( + | { + /** + * The name of the pivot table + * created in the database for this relationship. + */ + pivotTable?: string + /** + * @ignore + */ + pivotEntity?: never + } + | { + /** + * @ignore + */ + pivotTable?: never + /** + * A function that returns the data model + * representing the pivot table created in the + * database for this relationship. + */ + pivotEntity?: () => DmlEntity + } +) /** * Entity builder exposes the API to create an entity and define its @@ -44,8 +80,23 @@ export class EntityBuilder { } /** - * Define an entity or a model. The name should be unique across - * all the entities. + * This method defines a data model. + * + * @typeParam Schema - The type of the accepted schema in the second parameter of the method. + * + * @param {DefineOptions} nameOrConfig - Either the data model's name, or configurations to name the data model. + * The data model's name must be unique. + * @param {Schema} schema - The schema of the data model's properties. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * id: model.id(), + * name: model.text(), + * }) + * + * export default MyCustom */ define( nameOrConfig: DefineOptions, @@ -62,36 +113,102 @@ export class EntityBuilder { } /** - * Define an id property. Id properties are marked - * primary by default + * This method defines an automatically generated string ID property. + * + * By default, this property is considered to be the data model’s primary key. + * + * @param {ConstructorParameters[0]} options - The ID's options. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * id: model.id(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ id(options?: ConstructorParameters[0]) { return new IdProperty(options) } /** - * Define a text/string based column + * This method defines a string property. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * name: model.text(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ text() { return new TextProperty() } /** - * Define a boolean column + * This method defines a boolean property. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * hasAccount: model.boolean(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ boolean() { return new BooleanProperty() } /** - * Define an integer column + * This method defines a number property. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * age: model.number(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ number() { return new NumberProperty() } /** - * Define a numeric column. This property produces an additional + * This method defines a number property that expects large numbers, such as prices. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * price: model.bigNumber(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types + * + * @privateRemarks + * This property produces an additional * column - raw_{{ property_name }}, which stores the configuration * of bignumber (https://github.com/MikeMcl/bignumber.js) */ @@ -100,94 +217,198 @@ export class EntityBuilder { } /** - * Define an array column + * This method defines an array of strings property. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * names: model.array(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ array() { return new ArrayProperty() } /** - * Define a timestampz column + * This method defines a timestamp property. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * date_of_birth: model.dateTime(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ dateTime() { return new DateTimeProperty() } /** - * Define a JSON column to store data as a - * JSON string + * This method defines a property whose value is a stringified JSON object. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * metadata: model.json(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ json() { return new JSONProperty() } /** - * Define an enum column where only a pre-defined set - * of values are allowed. + * This method defines a property whose value can only be one of the specified values. + * + * @typeParam Values - The type of possible values. By default, it's `string`. + * + * @param {Values[]} values - An array of possible values. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * color: model.enum(["black", "white"]), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Types */ enum(values: Values[]) { return new EnumProperty(values) } /** - * Has one relationship defines a relationship between two entities - * where the owner of the relationship has exactly one instance - * of the related entity. + * This method defines a relationship between two data models, + * where the owner of the relationship has one record of the related + * data model. * - * For example: A user "hasOne" profile - * - * You may use the "belongsTo" relationship to define the inverse - * of the "hasOne" relationship + * For example: A user "hasOne" email. + * + * Use the {@link belongsTo} method to define the inverse of this relationship in + * the other data model. + * + * @typeParam T - The type of the entity builder passed as a first parameter. By default, it's + * a function returning the related model. + * + * @param {T} entityBuilder - A function that returns the data model this model is related to. + * @param {RelationshipOptions} options - The relationship's options. + * + * @example + * import { model } from "@medusajs/utils" + * + * const User = model.define("user", { + * id: model.id(), + * email: model.hasOne(() => Email), + * }) + * + * @customNamespace Relationship Methods */ hasOne(entityBuilder: T, options?: RelationshipOptions) { return new HasOne(entityBuilder, options || {}) } /** - * Define inverse of "hasOne" and "hasMany" relationship. + * This method defines the inverse of the {@link hasOne} or {@link hasMany} relationship. + * + * For example, a product "belongsTo" a store. + * + * @typeParam T - The type of the entity builder passed as a first parameter. By default, it's + * a function returning the related model. + * + * @param {T} entityBuilder - A function that returns the data model this model is related to. + * @param {RelationshipOptions} options - The relationship's options. + * + * @example + * const Product = model.define("product", { + * id: model.id(), + * store: model.belongsTo(() => Store, { + * mappedBy: "products", + * }), + * }) + * + * @customNamespace Relationship Methods */ belongsTo(entityBuilder: T, options?: RelationshipOptions) { return new BelongsTo(entityBuilder, options || {}) } /** - * Has many relationship defines a relationship between two entities - * where the owner of the relationship has many instance of the - * related entity. + * This method defines a relationship between two data models, + * where the owner of the relationship has many records of the related + * data model, but the related data model only has one owner. * - * For example: - * - * - A user "hasMany" books - * - A user "hasMany" addresses + * For example, a store "hasMany" products. + * + * @typeParam T - The type of the entity builder passed as a first parameter. By default, it's + * a function returning the related model. + * + * @param {T} entityBuilder - A function that returns the data model this model is related to. + * @param {RelationshipOptions} options - The relationship's options. + * + * @example + * import { model } from "@medusajs/utils" + * + * const Store = model.define("store", { + * id: model.id(), + * products: model.hasMany(() => Product), + * }) + * + * @customNamespace Relationship Methods */ hasMany(entityBuilder: T, options?: RelationshipOptions) { return new HasMany(entityBuilder, options || {}) } /** - * ManyToMany relationship defines a relationship between two entities - * where the owner of the relationship has many instance of the - * related entity via a pivot table. + * This method defines a relationship between two data models, + * where both data models have many related records. * - * For example: - * - * - A user has many teams. But a team has many users as well. So this - * relationship requires a pivot table to establish a many to many - * relationship between two entities + * For example, an order is associated with many products, and a product + * is associated with many orders. + * + * @typeParam T - The type of the entity builder passed as a first parameter. By default, it's + * a function returning the related model. + * + * @param {T} entityBuilder - A function that returns the data model this model is related to. + * @param {RelationshipOptions} options - The relationship's options. + * + * @example + * import { model } from "@medusajs/utils" + * + * const Order = model.define("order", { + * id: model.id(), + * products: model.manyToMany(() => Product), + * }) + * + * const Product = model.define("product", { + * id: model.id(), + * order: model.manyToMany(() => Order), + * }) + * + * @customNamespace Relationship Methods */ manyToMany( entityBuilder: T, - options?: RelationshipOptions & - ( - | { - pivotTable?: string - pivotEntity?: never - } - | { - pivotTable?: never - pivotEntity?: () => DmlEntity - } - ) + options?: ManyToManyOptions ) { return new ManyToMany(entityBuilder, options || {}) } diff --git a/packages/core/utils/src/dml/entity.ts b/packages/core/utils/src/dml/entity.ts index 8296fdc3b3..fe55441195 100644 --- a/packages/core/utils/src/dml/entity.ts +++ b/packages/core/utils/src/dml/entity.ts @@ -94,10 +94,27 @@ export class DmlEntity implements IDmlEntity { } /** - * Delete actions to be performed when the entity is deleted. For example: - * - * You can configure relationship data to be deleted when the current - * entity is deleted. + * This method configures which related data models an operation, such as deletion, + * should be cascaded to. + * + * For example, if a store is deleted, its product should also be deleted. + * + * @param options - The cascades configurations. They object's keys are the names of + * the actions, such as `deleted`, and the value is an array of relations that the + * action should be cascaded to. + * + * @example + * import { model } from "@medusajs/utils" + * + * const Store = model.define("store", { + * id: model.id(), + * products: model.hasMany(() => Product), + * }) + * .cascades({ + * delete: ["products"], + * }) + * + * @customNamespace Model Methods */ cascades( options: EntityCascades< @@ -123,7 +140,77 @@ export class DmlEntity implements IDmlEntity { } /** - * Adds indexes to be created at during model creation on the DML entity. + * This method defines indices on the data model. An index can be on multiple columns + * and have conditions. + * + * @param indexes - The index's configuration. + * + * @example + * An example of a simple index: + * + * ```ts + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * id: model.id(), + * name: model.text(), + * age: model.number() + * }).indexes([ + * { + * on: ["name", "age"], + * }, + * ]) + * + * export default MyCustom + * ``` + * + * To add a condition on the index, use the `where` option: + * + * ```ts + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * id: model.id(), + * name: model.text(), + * age: model.number() + * }).indexes([ + * { + * on: ["name", "age"], + * where: { + * age: 30 + * } + * }, + * ]) + * + * export default MyCustom + * ``` + * + * The condition can also be a negation. For example: + * + * ```ts + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * id: model.id(), + * name: model.text(), + * age: model.number() + * }).indexes([ + * { + * on: ["name", "age"], + * where: { + * age: { + * $ne: 30 + * } + * } + * }, + * ]) + * + * export default MyCustom + * ``` + * + * In this example, the index is created when the value of `age` doesn't equal `30`. + * + * @customNamespace Model Methods */ indexes(indexes: EntityIndex>[]) { for (const index of indexes) { diff --git a/packages/core/utils/src/dml/properties/base.ts b/packages/core/utils/src/dml/properties/base.ts index ed0b356e15..189cd0fff2 100644 --- a/packages/core/utils/src/dml/properties/base.ts +++ b/packages/core/utils/src/dml/properties/base.ts @@ -30,14 +30,43 @@ export abstract class BaseProperty implements PropertyType { declare $dataType: T /** - * Apply nullable modifier on the schema + * This method indicates that a property's value can be `null`. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * price: model.bigNumber().nullable(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Configuration Methods */ nullable() { return new NullableModifier(this) } /** - * Define an index on the property + * This method defines an index on a property. + * + * @param {string} name - The index's name. If not provided, + * Medusa generates the name. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * id: model.id(), + * name: model.text().index( + * "IDX_MY_CUSTOM_NAME" + * ), + * }) + * + * export default MyCustom + * + * @customNamespace Property Configuration Methods */ index(name?: string) { this.#indexes.push({ name, type: "index" }) @@ -45,7 +74,23 @@ export abstract class BaseProperty implements PropertyType { } /** - * Define a unique index on the property + * This method indicates that a property's value must be unique in the database. + * A unique index is created on the property. + * + * @param {string} name - The unique index's name. If not provided, + * Medusa generates the name. + * + * @example + * import { model } from "@medusajs/utils" + * + * const User = model.define("user", { + * email: model.text().unique(), + * // ... + * }) + * + * export default User + * + * @customNamespace Property Configuration Methods */ unique(name?: string) { this.#indexes.push({ name, type: "unique" }) @@ -53,7 +98,26 @@ export abstract class BaseProperty implements PropertyType { } /** - * Define default value for the property + * This method defines the default value of a property. + * + * @param {T} value - The default value. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * color: model + * .enum(["black", "white"]) + * .default("black"), + * age: model + * .number() + * .default(0), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Configuration Methods */ default(value: T) { this.#defaultValue = value diff --git a/packages/core/utils/src/dml/properties/id.ts b/packages/core/utils/src/dml/properties/id.ts index 549d56df8e..17fd670e81 100644 --- a/packages/core/utils/src/dml/properties/id.ts +++ b/packages/core/utils/src/dml/properties/id.ts @@ -13,7 +13,21 @@ export class IdProperty extends BaseProperty { } } - constructor(options?: { primaryKey?: boolean; prefix?: string }) { + constructor(options?: { + /** + * Whether the ID is the data model's primary key. + * + * @defaultValue true + */ + primaryKey?: boolean + /** + * By default, Medusa shortens the data model's name and uses it as the + * prefix of all IDs. For example, `cm_123`. + * + * Use this option to specify the prefix to use instead. + */ + prefix?: string + }) { super() this.dataType = { name: "id", diff --git a/packages/core/utils/src/dml/properties/text.ts b/packages/core/utils/src/dml/properties/text.ts index 8d07e487ce..68c730df38 100644 --- a/packages/core/utils/src/dml/properties/text.ts +++ b/packages/core/utils/src/dml/properties/text.ts @@ -12,12 +12,42 @@ export class TextProperty extends BaseProperty { } } + /** + * This method indicates that the property is the data model's primary key. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * code: model.text().primaryKey(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Configuration Methods + */ primaryKey() { this.dataType.options.primaryKey = true return this } + /** + * This method indicates that a text property is searchable. + * + * @example + * import { model } from "@medusajs/utils" + * + * const MyCustom = model.define("my_custom", { + * name: model.text().searchable(), + * // ... + * }) + * + * export default MyCustom + * + * @customNamespace Property Configuration Methods + */ searchable() { this.dataType.options.searchable = true diff --git a/packages/core/utils/tsconfig.json b/packages/core/utils/tsconfig.json index 11ca7eca56..66ea7e76b7 100644 --- a/packages/core/utils/tsconfig.json +++ b/packages/core/utils/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "./dist", "esModuleInterop": true, "declaration": true, + "declarationMap": true, "module": "commonjs", "moduleResolution": "node", "emitDecoratorMetadata": true, diff --git a/www/apps/resources/sidebar.mjs b/www/apps/resources/sidebar.mjs index a949eae761..65bb6e6de3 100644 --- a/www/apps/resources/sidebar.mjs +++ b/www/apps/resources/sidebar.mjs @@ -2130,6 +2130,44 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, ], }, + // { + // path: "/references/data-model", + // title: "Data Model API", + // childSidebarTitle: "Data Model API Reference", + // isChildSidebar: true, + // children: [ + // { + // path: "/references/data-model/define", + // title: "Define Method", + // hasTitleStyling: true, + // }, + // { + // path: "/references/data-model/property-types", + // title: "Property Types", + // hasTitleStyling: true, + // autogenerate_path: "/references/dml/Property_Types/methods", + // }, + // { + // path: "/references/data-model/relationship-methods", + // title: "Relationship Methods", + // hasTitleStyling: true, + // autogenerate_path: "/references/dml/Relationship_Methods/methods", + // }, + // { + // path: "/references/data-model/model-methods", + // title: "Model Methods", + // hasTitleStyling: true, + // autogenerate_path: "/references/dml/Model_Methods/methods", + // }, + // { + // path: "/references/data-model/property-configuration", + // title: "Property Configuration Methods", + // hasTitleStyling: true, + // autogenerate_path: + // "/references/dml/Property_Configuration_Methods/methods", + // }, + // ], + // }, ], }, { diff --git a/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts b/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts index cad0a80f05..aadf7954f2 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/custom-options.ts @@ -16,6 +16,16 @@ const customOptions: Record> = { name: "auth-provider", parentIgnore: true, }), + dml: getOptions({ + entryPointPath: [ + "packages/core/utils/src/dml/entity-builder.ts", + "packages/core/utils/src/dml/entity.ts", + "packages/core/utils/src/dml/properties/base.ts", + ], + tsConfigName: "utils.json", + name: "dml", + generateNamespaces: true, + }), file: getOptions({ entryPointPath: "packages/core/utils/src/file/abstract-file-provider.ts", tsConfigName: "utils.json", @@ -28,29 +38,11 @@ const customOptions: Record> = { name: "fulfillment-provider", parentIgnore: true, }), - "js-client": getOptions({ - entryPointPath: "packages/medusa-js/src/resources", - tsConfigName: "js-client.json", - name: "js-client", - plugin: ["typedoc-plugin-rename-defaults"], - exclude: [ - ...(baseOptions.exclude || []), - path.join(rootPathPrefix, "packages/medusa-js/src/resources/base.ts"), - ], - ignoreApi: true, - }), "medusa-config": getOptions({ entryPointPath: "packages/core/types/src/common/config-module.ts", tsConfigName: "types.json", name: "medusa-config", }), - "medusa-react": getOptions({ - entryPointPath: "packages/medusa-react/src/index.ts", - tsConfigName: "medusa-react.json", - name: "medusa-react", - generateNamespaces: true, - ignoreApi: true, - }), medusa: getOptions({ entryPointPath: "packages/medusa/src/index.js", tsConfigName: "medusa.json", @@ -96,11 +88,6 @@ const customOptions: Record> = { tsConfigName: "utils.json", name: "search", }), - services: getOptions({ - entryPointPath: "packages/medusa/src/services/index.ts", - tsConfigName: "medusa.json", - name: "services", - }), "tax-provider": getOptions({ entryPointPath: "packages/core/types/src/tax/provider.ts", tsConfigName: "types.json", @@ -117,11 +104,6 @@ const customOptions: Record> = { ...modules.map((moduleName) => `**/${moduleName}/**/*.ts`), ], }), - workflows: getOptions({ - entryPointPath: "packages/core/workflows-sdk/src/utils/composer/index.ts", - tsConfigName: "workflows.json", - name: "workflows", - }), utils: getOptions({ entryPointPath: "packages/core/utils/src/index.ts", tsConfigName: "utils.json", @@ -146,6 +128,11 @@ const customOptions: Record> = { "**/totals/**", ], }), + workflows: getOptions({ + entryPointPath: "packages/core/workflows-sdk/src/utils/composer/index.ts", + tsConfigName: "workflows.json", + name: "workflows", + }), } export default customOptions diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/dml.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/dml.ts new file mode 100644 index 0000000000..d956c00cd2 --- /dev/null +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/dml.ts @@ -0,0 +1,124 @@ +import { FormattingOptionsType } from "types" +import baseSectionsOptions from "../base-section-options.js" + +const dmlOptions: FormattingOptionsType = { + "^dml": { + expandMembers: true, + sections: { + ...baseSectionsOptions, + member_getterSetter: false, + member_returns: false, + }, + }, + "^modules/dml/page\\.mdx": { + reflectionDescription: + "This section of the documentation provides an API reference to the property types and methods used to create a data model.", + reflectionGroups: { + Classes: false, + Variables: false, + Properties: false, + Modules: false, + }, + frontmatterData: { + slug: "/references/data-model", + }, + reflectionTitle: { + fullReplacement: "Data Models API Reference", + }, + hideTocHeaders: true, + }, + "^dml/.*define": { + frontmatterData: { + slug: "/references/data-model/define", + }, + reflectionTitle: { + suffix: "Method - API Reference", + }, + }, + "^dml/.*Property_Types/page\\.mdx": { + frontmatterData: { + slug: "/references/data-model/property-types", + }, + reflectionDescription: + "The following methods are used to define the type of a property in a data model.", + reflectionTitle: { + suffix: "- API Reference", + }, + }, + "^dml/Property_Types": { + frontmatterData: { + slug: "/references/data-model/property-types/{{alias-lower}}", + sidebar_label: "{{alias}}", + }, + reflectionTitle: { + suffix: "Property Method - API Reference", + }, + }, + "^dml/.*Relationship_Methods/page\\.mdx": { + frontmatterData: { + slug: "/references/data-model/relationship-methods", + }, + reflectionDescription: + "The following methods are used to define a relationship between two data models.", + reflectionTitle: { + suffix: "- API Reference", + }, + }, + "^dml/Relationship_Methods": { + frontmatterData: { + slug: "/references/data-model/relationship-methods/{{alias-lower}}", + sidebar_label: "{{alias}}", + }, + reflectionTitle: { + suffix: "Relationship Method - API Reference", + }, + }, + "^dml/.*Model_Methods/page\\.mdx": { + frontmatterData: { + slug: "/references/data-model/model-methods", + }, + reflectionDescription: + "The following methods are used on a module to configure it.", + reflectionTitle: { + suffix: "- API Reference", + }, + }, + "^dml/Model_Methods": { + frontmatterData: { + slug: "/references/data-model/model-methods/{{alias-lower}}", + sidebar_label: "{{alias}}", + }, + reflectionTitle: { + suffix: "Method - API Reference", + }, + }, + "^dml/.*Property_Configuration_Methods/page\\.mdx": { + frontmatterData: { + slug: "/references/data-model/property-configuration", + }, + reflectionDescription: + "The following methods are used on a property to configure it.", + reflectionTitle: { + suffix: "- API Reference", + }, + }, + "^dml/Property_Configuration_Methods": { + frontmatterData: { + slug: "/references/data-model/property-configuration/{{alias-lower}}", + sidebar_label: "{{alias}}", + }, + reflectionTitle: { + suffix: "Method - API Reference", + }, + }, + "^dml/.*/types/.*": { + sections: { + ...baseSectionsOptions, + member_getterSetter: false, + member_returns: false, + member_declaration_children: true, + }, + }, +} + +export default dmlOptions diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/index.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/index.ts index b2c02559a7..2ecab4bd15 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/index.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-custom-options/index.ts @@ -11,9 +11,11 @@ import paymentProviderOptions from "./payment-provider.js" import searchOptions from "./search.js" import taxProviderOptions from "./tax-provider.js" import workflowsOptions from "./workflows.js" +import dmlOptions from "./dml.js" const mergerCustomOptions: FormattingOptionsType = { ...authProviderOptions, + ...dmlOptions, ...fileOptions, ...fulfillmentProviderOptions, ...jsClientOptions, diff --git a/www/utils/packages/typedoc-generate-references/src/constants/merger-options.ts b/www/utils/packages/typedoc-generate-references/src/constants/merger-options.ts index 616016a5ea..c8914df309 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/merger-options.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/merger-options.ts @@ -28,7 +28,7 @@ const mergerOptions: Partial = { objectLiteralTypeDeclarationStyle: "component", mdxOutput: true, maxLevel: 3, - allReflectionsHaveOwnDocument: [...modules, "workflows"], + allReflectionsHaveOwnDocument: [...modules, "dml", "workflows"], allReflectionsHaveOwnDocumentInNamespace: ["Utilities"], formatting: { "*": { diff --git a/www/utils/packages/typedoc-generate-references/src/constants/references.ts b/www/utils/packages/typedoc-generate-references/src/constants/references.ts index b21d76d40b..6d23dd988b 100644 --- a/www/utils/packages/typedoc-generate-references/src/constants/references.ts +++ b/www/utils/packages/typedoc-generate-references/src/constants/references.ts @@ -22,6 +22,7 @@ export const modules = [ const allReferences = [ ...modules, "auth-provider", + "dml", "file", "fulfillment-provider", "medusa-config", diff --git a/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts b/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts index 0737e63860..7015ed14e9 100644 --- a/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts +++ b/www/utils/packages/typedoc-plugin-custom/src/generate-namespace.ts @@ -7,6 +7,7 @@ import { Converter, DeclarationReflection, ParameterType, + Reflection, ReflectionCategory, ReflectionKind, } from "typedoc" @@ -31,7 +32,7 @@ export class GenerateNamespacePlugin { this.declareOptions() this.app.converter.on( - Converter.EVENT_CREATE_DECLARATION, + Converter.EVENT_RESOLVE, this.handleCreateDeclarationEvent.bind(this) ) this.app.converter.on( @@ -145,14 +146,17 @@ export class GenerateNamespacePlugin { * create categories in the last namespace if the * reflection has a category */ - attachCategories(reflection: DeclarationReflection) { + attachCategories( + reflection: DeclarationReflection, + comments: Comment | undefined + ) { if (!this.currentNamespaceHeirarchy.length) { return } const parentNamespace = this.currentNamespaceHeirarchy[this.currentNamespaceHeirarchy.length - 1] - reflection.comment?.blockTags + comments?.blockTags .filter((tag) => tag.tag === "@category") .forEach((tag) => { const categoryName = tag.content[0].text @@ -170,10 +174,10 @@ export class GenerateNamespacePlugin { }) } - handleCreateDeclarationEvent( - context: Context, - reflection: DeclarationReflection - ) { + handleCreateDeclarationEvent(context: Context, reflection: Reflection) { + if (!(reflection instanceof DeclarationReflection)) { + return + } this.readOptions() if (this.options?.parentNamespace && !this.parentNamespace) { this.parentNamespace = @@ -185,7 +189,8 @@ export class GenerateNamespacePlugin { this.currentNamespaceHeirarchy.push(this.parentNamespace) } this.currentContext = context - reflection.comment?.blockTags + const comments = this.getReflectionComments(reflection) + comments?.blockTags .filter((tag) => tag.tag === "@customNamespace") .forEach((tag) => { this.generateNamespaceFromTag({ @@ -202,8 +207,8 @@ export class GenerateNamespacePlugin { this.currentContext?.addChild(reflection) }) - reflection.comment?.removeTags("@customNamespace") - this.attachCategories(reflection) + comments?.removeTags("@customNamespace") + this.attachCategories(reflection, comments) this.currentContext = undefined this.currentNamespaceHeirarchy = [] } @@ -251,6 +256,20 @@ export class GenerateNamespacePlugin { this.scannedComments = true } + getReflectionComments( + reflection: DeclarationReflection + ): Comment | undefined { + if (reflection.comment) { + return reflection.comment + } + + // try to retrieve comment from signature + if (!reflection.signatures?.length) { + return + } + return reflection.signatures.find((signature) => signature.comment)?.comment + } + // for debugging printCurrentHeirarchy() { return this.currentNamespaceHeirarchy.map((heirarchy) => heirarchy.name) diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/if-show-returns.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/if-show-returns.ts index 4ddb3d46fa..f893fdc42d 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/if-show-returns.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/if-show-returns.ts @@ -9,7 +9,10 @@ export default function (theme: MarkdownTheme) { function (this: SignatureReflection, options: Handlebars.HelperOptions) { this.parent = getCorrectDeclarationReflection(this.parent, theme) || this.parent - return this.type && !this.parent?.kindOf(ReflectionKind.Constructor) + const { sections } = theme.getFormattingOptionsForLocation() + return sections?.member_returns !== false && + this.type && + !this.parent?.kindOf(ReflectionKind.Constructor) ? options.fn(this) : options.inverse(this) } diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/parameter-component.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/parameter-component.ts index 95a3927036..adcfde7cad 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/parameter-component.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/parameter-component.ts @@ -17,13 +17,19 @@ export default function (theme: MarkdownTheme) { const parameters = this.reduce( (acc: ReflectionParameterType[], current) => parseParams(current, acc), [] - ).map((parameter) => - reflectionComponentFormatter({ - reflection: parameter, - level: 1, - maxLevel, - }) ) + .filter((parameter) => { + // remove parameters that are supposed to be nested + return !parameter.name.includes(".") + }) + .map((parameter) => + reflectionComponentFormatter({ + reflection: parameter, + level: 1, + maxLevel, + project: theme.project, + }) + ) return formatParameterComponent({ parameterComponent, diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/toc.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/toc.ts index 8c489fbacd..a33abfea61 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/toc.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/resources/helpers/toc.ts @@ -14,6 +14,7 @@ export default function (theme: MarkdownTheme) { const md: string[] = [] const { hideInPageTOC } = theme + const { hideTocHeaders } = theme.getFormattingOptionsForLocation() const isVisible = this.groups?.some((group) => group.allChildrenHaveOwnDocument() @@ -44,7 +45,9 @@ export default function (theme: MarkdownTheme) { }) } else { if (!hideInPageTOC || group.allChildrenHaveOwnDocument()) { - md.push(`${headingLevel} ${groupTitle}\n\n`) + if (!hideTocHeaders) { + md.push(`${headingLevel} ${groupTitle}\n\n`) + } pushGroup(group, md) md.push("\n") } diff --git a/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts b/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts index b14d49d3ab..cefedad02d 100644 --- a/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts +++ b/www/utils/packages/typedoc-plugin-markdown-medusa/src/utils/reflection-formatter.ts @@ -162,7 +162,7 @@ export function reflectionComponentFormatter({ : getTypeChildren({ reflectionType: reflection.type!, project: project || reflection.project, - maxLevel, + maxLevel: maxLevel || MarkdownTheme.MAX_LEVEL, }) children diff --git a/www/utils/packages/types/lib/index.d.ts b/www/utils/packages/types/lib/index.d.ts index 83298f4d15..4e7c85d7cb 100644 --- a/www/utils/packages/types/lib/index.d.ts +++ b/www/utils/packages/types/lib/index.d.ts @@ -29,6 +29,7 @@ export type SectionKey = | "member_sources_definedIn" | "members_group_categories" | "members_categories" + | "member_returns" | "title_reflectionPath" | "reflection_comment" | "reflection_typeParameters" @@ -78,6 +79,7 @@ export type FormattingOptionType = { startSections?: string[] endSections?: string[] shouldIncrementAfterStartSections?: boolean + hideTocHeaders?: boolean } export declare module "typedoc" { diff --git a/www/utils/packages/utils/src/get-type-children.ts b/www/utils/packages/utils/src/get-type-children.ts index 1a31c7808b..0284fd2879 100644 --- a/www/utils/packages/utils/src/get-type-children.ts +++ b/www/utils/packages/utils/src/get-type-children.ts @@ -34,6 +34,19 @@ export function getTypeChildren({ ) }) break + case "union": + reflectionType.types.forEach((childItem) => { + // TODO this should ensure that the items are unique. + children.push( + ...getTypeChildren({ + reflectionType: childItem, + project, + level: level + 1, + maxLevel, + }) + ) + }) + break case "reference": // eslint-disable-next-line no-case-declarations const referencedReflection = reflectionType.reflection @@ -53,7 +66,7 @@ export function getTypeChildren({ children = getTypeChildren({ reflectionType: referencedReflection.type, project, - level: level + 1, + level, maxLevel, }) }