Skip to content

Commit baf616d

Browse files
authored
Merge pull request #560 from commerce-docs/refactor/table-generator-shared-lib
Refactor/table generator shared lib
2 parents 59ee044 + 05c58b4 commit baf616d

File tree

6 files changed

+83
-29
lines changed

6 files changed

+83
-29
lines changed

_dropin-templates/dropin-container.mdx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@ CONTAINER_DESCRIPTION
2020

2121
The `CONTAINER_NAME` container provides the following configuration options:
2222

23-
<TableWrapper nowrap={[0]}>
24-
25-
| Property | Type | Required | Description |
26-
|----------|------|----------|-------------|
23+
{/*
24+
IMPORTANT: Do not wrap CONFIGURATIONS_TABLE in TableWrapper or add a table header.
25+
The generator's generatePropertyTable() function already includes both.
26+
Adding them here will cause nested TableWrapper components and duplicate headers.
27+
*/}
2728
CONFIGURATIONS_TABLE
2829

29-
</TableWrapper>
30-
3130
## Slots
3231

3332
SLOTS_CONTENT

scripts/@generate-container-docs.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,21 @@ function generateSlotsContent(containerName, slots) {
163163
*/
164164
function generateContainersMDX(repoName, repoConfig, containers, version, enrichmentData = null) {
165165
const template = readTemplate('dropin-container.mdx');
166+
167+
// Validate template: Check if it contains TableWrapper around CONFIGURATIONS_TABLE
168+
// This would cause nested wrappers since generatePropertyTable() already adds them
169+
if (template.includes('<TableWrapper') && template.includes('CONFIGURATIONS_TABLE')) {
170+
const configSection = template.substring(
171+
template.indexOf('## Configuration'),
172+
template.indexOf('## Slots')
173+
);
174+
if (configSection.includes('<TableWrapper') && configSection.includes('CONFIGURATIONS_TABLE')) {
175+
logger.warn('⚠️ Template contains TableWrapper in Configuration section!');
176+
logger.warn(' This will cause nested wrappers. Remove wrapper from template.');
177+
logger.warn(' The generatePropertyTable() function already includes the wrapper.');
178+
}
179+
}
180+
166181
const containerDocs = new Map();
167182

168183
for (const containerInfo of containers) {

scripts/@generate-function-docs.js

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { EnrichmentLoader } from './lib/core/enrichment-loader.js';
4343
import { TypeExtractor } from './lib/core/type-extractor.js';
4444
import { validateAllFunctionDocs } from './lib/function-type-validator.js';
4545
import { generateNoFunctionsPage } from './lib/markdown/empty-state-generator.js';
46+
import { generatePropertyTable } from './lib/markdown/table-generator.js';
4647

4748
const projectRoot = getProjectRoot();
4849

@@ -1203,15 +1204,10 @@ function generateFunctionsMDX(repoName, repoConfig, scannedData, version, enrich
12031204
const parameters = parseTypeScriptParameters(signature.params);
12041205

12051206
if (parameters.length > 0) {
1206-
functionsContent += `<TableWrapper nowrap={[0, 1]}>\n\n`;
1207+
// Transform parameters into format expected by generatePropertyTable
1208+
const tableItems = [];
12071209

1208-
// Header row
1209-
functionsContent += `| Parameter | Type | Req? | Description |\n`;
1210-
functionsContent += `|---|---|---|---|\n`;
1211-
1212-
// Parameter rows
12131210
parameters.forEach(param => {
1214-
const required = param.optional ? 'No' : 'Yes';
12151211
let type = param.type;
12161212

12171213
// Check if this is an inline object type with nested properties
@@ -1224,10 +1220,6 @@ function generateFunctionsMDX(repoName, repoConfig, scannedData, version, enrich
12241220
if (nestedProps.length > 0) {
12251221
// Show each nested property as a separate row
12261222
nestedProps.forEach(nestedProp => {
1227-
const nestedRequired = nestedProp.optional ? 'No' : 'Yes';
1228-
let nestedType = `\`${nestedProp.type}\``;
1229-
1230-
// Get description using parameter patterns with fallback hierarchy
12311223
const description = getParameterDescription(
12321224
nestedProp.name,
12331225
enrichment,
@@ -1236,7 +1228,12 @@ function generateFunctionsMDX(repoName, repoConfig, scannedData, version, enrich
12361228
func.name
12371229
);
12381230

1239-
functionsContent += `| \`${nestedProp.name}\` | ${nestedType} | ${nestedRequired} | ${description} |\n`;
1231+
tableItems.push({
1232+
name: nestedProp.name,
1233+
type: nestedProp.type,
1234+
required: !nestedProp.optional,
1235+
description: description
1236+
});
12401237
});
12411238
return; // Skip the default handling for this parameter
12421239
}
@@ -1255,9 +1252,6 @@ function generateFunctionsMDX(repoName, repoConfig, scannedData, version, enrich
12551252
}
12561253
}
12571254

1258-
// Wrap type in backticks for inline code
1259-
type = `\`${type}\``;
1260-
12611255
// Get description using parameter patterns with fallback hierarchy
12621256
const description = getParameterDescription(
12631257
param.name,
@@ -1266,10 +1260,20 @@ function generateFunctionsMDX(repoName, repoConfig, scannedData, version, enrich
12661260
repoName,
12671261
func.name
12681262
);
1269-
functionsContent += `| \`${param.name}\` | ${type} | ${required} | ${description} |\n`;
1263+
1264+
tableItems.push({
1265+
name: param.name,
1266+
type: type,
1267+
required: !param.optional,
1268+
description: description
1269+
});
12701270
});
12711271

1272-
functionsContent += `\n</TableWrapper>\n\n`;
1272+
// Use shared library to generate table
1273+
functionsContent += generatePropertyTable(tableItems, {
1274+
nowrapColumns: [0, 1]
1275+
});
1276+
functionsContent += '\n\n';
12731277
}
12741278
}
12751279

scripts/lib/markdown/table-generator.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,47 @@ export function sanitizeText(text) {
4444
.trim();
4545
}
4646

47+
/**
48+
* Sanitize inline code (types, code snippets) for use in markdown table cells
49+
*
50+
* This is a lighter sanitizer for content that will be wrapped in backticks.
51+
* Inside backticks, most characters are literal and don't need escaping.
52+
* Only escapes characters that would break inline code blocks.
53+
*
54+
* @param {string} text - Text to sanitize (will be wrapped in backticks)
55+
* @returns {string} Sanitized text safe for inline code in markdown tables
56+
*
57+
* @example
58+
* sanitizeInlineCode('(item: CartModel[\'items\'][0]) => string')
59+
* // Returns: '(item: CartModel[\'items\'][0]) => string' (unchanged)
60+
*/
61+
export function sanitizeInlineCode(text) {
62+
if (!text) return '';
63+
64+
return text
65+
.replace(/\\/g, '\\\\') // Escape backslashes FIRST
66+
.replace(/\n/g, ' ') // Remove line breaks
67+
.replace(/\r/g, '') // Remove carriage returns
68+
.replace(/`/g, '\\`') // Escape backticks (would break inline code)
69+
.replace(/\|/g, '\\|') // Escape pipes (would break table cell)
70+
.replace(/\s+/g, ' ') // Collapse multiple spaces
71+
.trim();
72+
}
73+
4774
/**
4875
* Generate a markdown table for properties/parameters/configurations
4976
*
5077
* Creates a markdown table with columns for name, type, required status, and description.
5178
* Automatically wraps in TableWrapper component if nowrap columns are specified.
5279
*
80+
* **IMPORTANT**: This function generates a COMPLETE table including:
81+
* - TableWrapper component (if nowrapColumns specified)
82+
* - Table header row
83+
* - Table data rows
84+
*
85+
* Templates should NOT wrap the output in TableWrapper or add headers.
86+
* Doing so will cause nested wrappers and duplicate headers.
87+
*
5388
* @param {Array<Object>} items - Array of items to include in table
5489
* @param {string} items[].name - Property/parameter name
5590
* @param {string} items[].type - TypeScript type
@@ -59,13 +94,14 @@ export function sanitizeText(text) {
5994
* @param {Array<number>} options.nowrapColumns - Column indices that should not wrap (0-based)
6095
* @param {string} options.emptyMessage - Message to show if table is empty
6196
* @param {boolean} options.includeRequired - Whether to include Required column (default: true)
62-
* @returns {string} Markdown table with optional TableWrapper
97+
* @returns {string} Complete markdown table with optional TableWrapper
6398
*
6499
* @example
65100
* const items = [
66101
* { name: 'sku', type: 'string', required: true, description: 'Product SKU' },
67102
* { name: 'quantity', type: 'number', required: false, description: 'Quantity to add' }
68103
* ];
104+
* // Returns: <TableWrapper nowrap={[0,1]}>\n\n| Parameter | Type | ... \n</TableWrapper>
69105
* generatePropertyTable(items, { nowrapColumns: [0, 1] })
70106
*/
71107
export function generatePropertyTable(items, options = {}) {
@@ -100,7 +136,7 @@ export function generatePropertyTable(items, options = {}) {
100136
// Generate data rows
101137
for (const item of items) {
102138
const name = `\`${item.name}\``;
103-
const type = `\`${sanitizeText(item.type)}\``;
139+
const type = `\`${sanitizeInlineCode(item.type)}\``; // Use sanitizeInlineCode for types
104140
const required = item.required ? 'Yes' : 'No';
105141
const description = sanitizeText(item.description || '');
106142

src/content/docs/dropins/checkout/slots.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Learn about the slots provided in the checkout drop-in component.
1414

1515
## Title slots
1616

17-
The `TitleProps` interface defines slots for the [`Title`](/dropins/checkout/containers/#title-and-heading-customization) component. These slots enable you to customize the title content displayed in specific containers.
17+
The `TitleProps` interface defines slots for the [`Title`](/dropins/checkout/containers/) component. These slots enable you to customize the title content displayed in specific containers.
1818

1919
```ts
2020
export interface TitleProps {

src/content/docs/releases/changelog.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,11 @@ import Aside from '@components/Aside.astro';
215215

216216
The **[`Event Handling`](/dropins/all/events/) has been documented** within the list of events emitted and subscribed by the checkout drop-in component containers.
217217

218-
A new **[`Active`](/dropins/checkout/containers/#active-property) property has been added** for all containers: This property activates/deactivates the container.
218+
A new **[`Active`](/dropins/checkout/containers/) property has been added** for all containers: This property activates/deactivates the container.
219219

220-
A new **[`AutoSync`](/dropins/checkout/containers/#autosync-property) property has been added** for some containers: This property allows the container automatically synchronizing its state changes with the backend.
220+
A new **[`AutoSync`](/dropins/checkout/containers/) property has been added** for some containers: This property allows the container automatically synchronizing its state changes with the backend.
221221

222-
A new **[`TitleProps`](/dropins/checkout/containers/#title-and-heading-customization) interface has been created** to customize the title and header of some containers.
222+
A new **[`TitleProps`](/dropins/checkout/containers/) interface has been created** to customize the title and header of some containers.
223223

224224
The **[`BillToShippingAddress`](/dropins/checkout/containers/bill-to-shipping-address/) container configuration structure has been modified.** A new property has been added to the `BillToShippingAddressProps` interface:
225225

0 commit comments

Comments
 (0)