diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index 4c2d346..cb83dff 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -2,7 +2,8 @@ "type-aliases/EntitiesModule": [ "interfaces/EntityHandler", "type-aliases/EntityRecord", - "interfaces/EntityTypeRegistry" + "interfaces/EntityTypeRegistry", + "type-aliases/SortField" ], "interfaces/FunctionsModule": [ "type-aliases/FunctionName", diff --git a/scripts/mintlify-post-processing/file-processing/file-processing.js b/scripts/mintlify-post-processing/file-processing/file-processing.js index 158843f..437639c 100755 --- a/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1220,6 +1220,79 @@ function applyNonExposedTypeLinkRemoval(dir, exposedTypeNames) { } } +/** + * Add clickable links for types in ParamFields that reference types on the same page + */ +function addTypeLinksToParamFields(dir) { + if (!fs.existsSync(dir)) return; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const entryPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + addTypeLinksToParamFields(entryPath); + } else if ( + entry.isFile() && + (entry.name.endsWith(".mdx") || entry.name.endsWith(".md")) + ) { + let content = fs.readFileSync(entryPath, "utf-8"); + let modified = false; + + // Integrate clickable link into the description for SortField type + // Pattern: \n\nSort parameter, ... + // Replace with: \n\nA [`SortField`](#sortfield) specifying sort order, ... + const paramFieldPattern = /(]*type=")(SortField<([^>]*)>)("[^>]*>\n\n)Sort parameter,/g; + + content = content.replace(paramFieldPattern, (match, prefix, fullType, generic, suffix) => { + modified = true; + return `${prefix}${fullType}${suffix}A [\`${fullType}\`](#sortfield) specifying sort order,`; + }); + + if (modified) { + fs.writeFileSync(entryPath, content, "utf-8"); + console.log(`Added type links to ParamFields: ${path.relative(DOCS_DIR, entryPath)}`); + } + } + } +} + +/** + * Clean up SortField type signature to be more readable + */ +function cleanupSortFieldSignature(dir) { + if (!fs.existsSync(dir)) return; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const entryPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + cleanupSortFieldSignature(entryPath); + } else if ( + entry.isFile() && + (entry.name.endsWith(".mdx") || entry.name.endsWith(".md")) + ) { + let content = fs.readFileSync(entryPath, "utf-8"); + let modified = false; + + // Replace the complex SortField signature with a cleaner version + // Match: > **SortField**\<`T`\> = ... & ... | `` `+${(...) & (...)}` `` | `` `-${(...) & (...)}` `` + // Replace with: > **SortField**\<`T`\> = `string` | `` `+${string}` `` | `` `-${string}` `` + const sortFieldSignaturePattern = /> \*\*SortField\*\*\\<`T`\\> = \.\.\. & \.\.\. \| `` `\+\$\{\(\.\.\.\) & \(\.\.\.\)\}` `` \| `` `-\$\{\(\.\.\.\) & \(\.\.\.\)\}` ``/; + + if (sortFieldSignaturePattern.test(content)) { + content = content.replace( + sortFieldSignaturePattern, + "> **SortField**\\<`T`\\> = `keyof T` | `` `+${keyof T}` `` | `` `-${keyof T}` ``" + ); + modified = true; + } + + if (modified) { + fs.writeFileSync(entryPath, content, "utf-8"); + console.log(`Cleaned SortField signature: ${path.relative(DOCS_DIR, entryPath)}`); + } + } + } +} + /** * Main function */ @@ -1288,6 +1361,12 @@ function main() { const appendedArticles = loadAppendedArticlesConfig(); applyAppendedArticles(appendedArticles); + // Add clickable links for types in ParamFields + addTypeLinksToParamFields(DOCS_DIR); + + // Clean up SortField signature specifically (before general signature cleanup) + cleanupSortFieldSignature(DOCS_DIR); + // Clean up signatures: fix truncated generics, simplify keyof constraints, break long lines applySignatureCleanup(DOCS_DIR); diff --git a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js index a5388be..759eed7 100644 --- a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js +++ b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js @@ -289,7 +289,23 @@ function parseParametersWithExpansion( if (!line) return null; const trimmed = line.trim(); - // Handle [`TypeName`](link) format first (backticks inside the link) + // Handle [`TypeName`](link)\<`T`\> format (with generics after the link) + const linkWithBackticksAndGenericsMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)(.*)$/); + if (linkWithBackticksAndGenericsMatch) { + const typeName = linkWithBackticksAndGenericsMatch[1]; + const link = linkWithBackticksAndGenericsMatch[2]; + const generics = linkWithBackticksAndGenericsMatch[3].trim(); + + // If there are generics, append them to the type name (cleaning up markdown escapes) + const fullType = generics ? typeName + generics.replace(/\\/g, '') : typeName; + + return { + type: fullType, + link: link, + }; + } + + // Handle [`TypeName`](link) format (backticks inside the link, no generics) const linkWithBackticksMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)$/); if (linkWithBackticksMatch) { return { @@ -518,6 +534,7 @@ function parseParametersWithExpansion( params.push({ name: cleanName, type: type, + typeLink: typeLink, // Preserve the link description: descriptionLines.join("\n").trim(), optional, nested, @@ -571,7 +588,23 @@ function parseParameters( if (!line) return null; const trimmed = line.trim(); - // Handle [`TypeName`](link) format first (backticks inside the link) + // Handle [`TypeName`](link)\<`T`\> format (with generics after the link) + const linkWithBackticksAndGenericsMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)(.*)$/); + if (linkWithBackticksAndGenericsMatch) { + const typeName = linkWithBackticksAndGenericsMatch[1]; + const link = linkWithBackticksAndGenericsMatch[2]; + const generics = linkWithBackticksAndGenericsMatch[3].trim(); + + // If there are generics, append them to the type name (cleaning up markdown escapes) + const fullType = generics ? typeName + generics.replace(/\\/g, '') : typeName; + + return { + type: fullType, + link: link, + }; + } + + // Handle [`TypeName`](link) format (backticks inside the link, no generics) const linkWithBackticksMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)$/); if (linkWithBackticksMatch) { return { @@ -826,16 +859,16 @@ function buildParamFieldsSection( for (const param of params) { const requiredAttr = param.optional ? "" : " required"; - // Track non-primitive parameter types for suppression - - fieldsOutput += `\n`; + // Clean up the type string by removing markdown backticks + let typeAttr = param.type.replace(/`/g, ''); + fieldsOutput += `\n`; // Always show description in ParamField if it exists if (param.description) { - fieldsOutput += `\n${param.description}\n`; + fieldsOutput += `\n${param.description}`; } - fieldsOutput += "\n\n"; + fieldsOutput += "\n\n\n"; // If param has nested fields, wrap them in an Accordion if (param.nested.length > 0) { diff --git a/scripts/mintlify-post-processing/types-to-delete-after-processing.json b/scripts/mintlify-post-processing/types-to-delete-after-processing.json index 1b79c6c..392e12e 100644 --- a/scripts/mintlify-post-processing/types-to-delete-after-processing.json +++ b/scripts/mintlify-post-processing/types-to-delete-after-processing.json @@ -1,5 +1,6 @@ [ "DeleteManyResult", "DeleteResult", - "ImportResult" + "ImportResult", + "SortField" ] diff --git a/scripts/mintlify-post-processing/types-to-expose.json b/scripts/mintlify-post-processing/types-to-expose.json index 2cd803c..20229cf 100644 --- a/scripts/mintlify-post-processing/types-to-expose.json +++ b/scripts/mintlify-post-processing/types-to-expose.json @@ -19,5 +19,6 @@ "ImportResult", "IntegrationsModule", "CoreIntegrations", + "SortField", "SsoModule" ] diff --git a/src/index.ts b/src/index.ts index 4ae03a9..d772c1a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,6 +44,7 @@ export type { RealtimeEventType, RealtimeEvent, RealtimeCallback, + SortField, } from "./modules/entities.types.js"; export type { diff --git a/src/modules/entities.types.ts b/src/modules/entities.types.ts index ebc04c4..3376ff3 100644 --- a/src/modules/entities.types.ts +++ b/src/modules/entities.types.ts @@ -61,13 +61,16 @@ export interface ImportResult { /** * Sort field type for entity queries. * - * Supports ascending (no prefix or `'+'`) and descending (`'-'`) sorting. + * Accepts any field name from the entity type with an optional prefix: + * - `'+'` prefix or no prefix: ascending sort + * - `'-'` prefix: descending sort * * @typeParam T - The entity type to derive sortable fields from. * * @example * ```typescript - * // Ascending sort (default) + * // Specify sort direction by prefixing field names with + or - + * // Ascending sort * 'created_date' * '+created_date' * @@ -81,7 +84,7 @@ export type SortField = | `-${keyof T & string}`; /** - * Fields added by the server to every entity record (id, dates, created_by, etc.). + * Fields added by the server to every entity record, such as `id`, `created_date`, `updated_date`, and `created_by`. */ interface ServerEntityFields { /** Unique identifier of the record */ @@ -108,8 +111,7 @@ export interface EntityTypeRegistry {} * * @example * ```typescript - * import type { EntityRecord } from '@base44/sdk'; - * + * // Using EntityRecord to get the complete type for an entity * // Combine your schema with server fields (id, created_date, etc.) * type TaskRecord = EntityRecord['Task']; *