From cb3338820274b728e8316afc1df745f4d658105c Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 22 Dec 2025 14:10:39 +0200 Subject: [PATCH] docs: add line highlight validation (#14380) * docs: add line highlight validation * add to all projects * fixes * fixes * fix * fixes --- www/apps/api-reference/next.config.mjs | 2 + .../customize-admin/route/page.mdx | 8 +- .../api-routes/retrieve-custom-links/page.mdx | 2 +- .../data-models/manage-relationships/page.mdx | 4 +- .../module-links/read-only/page.mdx | 2 +- .../app/learn/fundamentals/modules/page.mdx | 2 +- www/apps/book/next.config.mjs | 2 + www/apps/cloud/next.config.mjs | 2 + .../inventory/inventory-kit/page.mdx | 4 +- .../examples/guides/quote-management/page.mdx | 6 +- .../tutorials/loyalty-points/page.mdx | 4 +- .../tutorials/phone-auth/page.mdx | 10 +- .../tutorials/preorder/page.mdx | 70 +++-- .../tutorials/product-builder/page.mdx | 12 +- .../cache/redis/page.mdx | 2 +- .../workflow-engine/redis/page.mdx | 6 +- .../app/integrations/guides/avalara/page.mdx | 6 +- .../integrations/guides/contentful/page.mdx | 2 +- .../app/integrations/guides/payload/page.mdx | 14 +- .../app/integrations/guides/sanity/page.mdx | 8 +- .../integrations/guides/shipstation/page.mdx | 12 +- .../guides/storefront-returns/page.mdx | 14 +- .../app/plugins/guides/wishlist/page.mdx | 4 +- .../examples/standard/page.mdx | 6 +- .../examples/standard/page.mdx | 14 +- .../examples/restaurant-delivery/page.mdx | 4 +- .../marketplace/examples/vendors/page.mdx | 11 +- .../subscriptions/examples/standard/page.mdx | 12 +- .../example/storefront/page.mdx | 8 +- .../cart/retrieve/page.mdx | 1 - .../checkout/address/page.mdx | 2 - .../checkout/email/page.mdx | 1 - .../checkout/shipping/page.mdx | 12 +- .../customers/addresses/page.mdx | 4 - .../customers/login/page.mdx | 2 +- .../customers/profile/page.mdx | 1 - .../guides/express-checkout/page.mdx | 4 +- .../localization/page.mdx | 6 +- .../products/categories/list/page.mdx | 7 +- .../categories/nested-categories/page.mdx | 7 +- .../products/categories/products/page.mdx | 5 +- .../products/categories/retrieve/page.mdx | 15 +- .../products/collections/list/page.mdx | 7 +- .../products/collections/products/page.mdx | 5 +- .../products/collections/retrieve/page.mdx | 14 +- .../products/list/page.mdx | 6 +- .../products/retrieve/page.mdx | 13 +- .../regions/context/page.mdx | 2 +- .../regions/list/page.mdx | 6 +- www/apps/resources/next.config.mjs | 2 + www/apps/ui/next.config.mjs | 2 + www/apps/user-guide/next.config.mjs | 2 + www/packages/docs-utils/src/estree-to-js.ts | 54 +++- .../src/broken-link-checker.ts | 4 +- .../src/cross-project-links.ts | 2 +- .../remark-rehype-plugins/src/index.ts | 1 + .../src/utils/component-link-fixer.ts | 2 +- .../src/validate-highlights.ts | 253 ++++++++++++++++++ www/packages/types/src/remark-rehype.ts | 62 ++++- 59 files changed, 514 insertions(+), 243 deletions(-) create mode 100644 www/packages/remark-rehype-plugins/src/validate-highlights.ts diff --git a/www/apps/api-reference/next.config.mjs b/www/apps/api-reference/next.config.mjs index d19e939794..3989985d47 100644 --- a/www/apps/api-reference/next.config.mjs +++ b/www/apps/api-reference/next.config.mjs @@ -5,6 +5,7 @@ import rehypeSlug from "rehype-slug" import { brokenLinkCheckerPlugin, crossProjectLinksPlugin, + validateHighlightsPlugin, } from "remark-rehype-plugins" import path from "path" import { catchBadRedirects } from "build-scripts" @@ -93,6 +94,7 @@ const withMDX = createMDX({ tagName: "code", }, ], + [validateHighlightsPlugin, { verbose: false }], [rehypeSlug], ], development: process.env.NODE_ENV === "development", diff --git a/www/apps/book/app/learn/customization/customize-admin/route/page.mdx b/www/apps/book/app/learn/customization/customize-admin/route/page.mdx index d8780334f7..89442860a1 100644 --- a/www/apps/book/app/learn/customization/customize-admin/route/page.mdx +++ b/www/apps/book/app/learn/customization/customize-admin/route/page.mdx @@ -197,10 +197,10 @@ So, to add the UI route at the `localhost:9000/app/brands` path, create the file ![Directory structure of the Medusa application after adding the UI route.](https://res.cloudinary.com/dza7lstvk/image/upload/v1733472011/Medusa%20Book/brands-admin-dir-overview-3_syytld.jpg) export const uiRouteHighlights = [ - ["8", "BrandsPage", "The UI route that displays a new page."], - ["23", "defineRouteConfig", "Export config to add a link for the UI route in the sidebar."], - ["24", "label", "The sidebar item's label."], - ["25", "icon", "The sidebar item's icon."] + ["10", "BrandsPage", "The UI route that displays a new page."], + ["20", "defineRouteConfig", "Export config to add a link for the UI route in the sidebar."], + ["21", "label", "The sidebar item's label."], + ["22", "icon", "The sidebar item's icon."] ] ```tsx title="src/admin/routes/brands/page.tsx" highlights={uiRouteHighlights} diff --git a/www/apps/book/app/learn/fundamentals/api-routes/retrieve-custom-links/page.mdx b/www/apps/book/app/learn/fundamentals/api-routes/retrieve-custom-links/page.mdx index f1ed1bdad2..b086ddc981 100644 --- a/www/apps/book/app/learn/fundamentals/api-routes/retrieve-custom-links/page.mdx +++ b/www/apps/book/app/learn/fundamentals/api-routes/retrieve-custom-links/page.mdx @@ -56,7 +56,7 @@ Learn how to create a middleware in the [Middlewares](../middlewares/page.mdx) c export const highlights = [ - ["10", "req.allowed", "Modify the allowed fields and relations to be retrieved"], + ["9", "req.allowed", "Modify the allowed fields and relations to be retrieved"], ] ```ts title="src/api/middlewares.ts" highlights={highlights} diff --git a/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx b/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx index 68a24d9fa6..6c2e03fd6f 100644 --- a/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx +++ b/www/apps/book/app/learn/fundamentals/data-models/manage-relationships/page.mdx @@ -49,8 +49,8 @@ When you create a record of a data model that has one of another, pass the ID of For example, assuming you have the [User and Email data models from the previous chapter](../relationships/page.mdx#one-to-one-relationship), set a user's email ID as follows: export const hasOneHighlights = [ - ["4", "email_id", "The ID of the email that the user has."], - ["11", "email_id", "The ID of the email that the user has."] + ["4", "email", "The ID of the email that the user has."], + ["11", "email", "The ID of the email that the user has."] ] ```ts highlights={hasOneHighlights} diff --git a/www/apps/book/app/learn/fundamentals/module-links/read-only/page.mdx b/www/apps/book/app/learn/fundamentals/module-links/read-only/page.mdx index 8710604ebc..6cd7a022a8 100644 --- a/www/apps/book/app/learn/fundamentals/module-links/read-only/page.mdx +++ b/www/apps/book/app/learn/fundamentals/module-links/read-only/page.mdx @@ -576,7 +576,7 @@ You can also create a `listAndCount` method to retrieve the posts with paginatio Now, you can use Query to retrieve a product and its linked post from the CMS: export const queryHighlights = [ - ["3", `"cms_post"`, "The `alias` of the virtual data model in the link configuration."] + ["3", `"cms_post.*"`, "The `alias` of the virtual data model in the link configuration."] ] ```ts highlights={queryHighlights} diff --git a/www/apps/book/app/learn/fundamentals/modules/page.mdx b/www/apps/book/app/learn/fundamentals/modules/page.mdx index 11afc9df66..5ae833c23e 100644 --- a/www/apps/book/app/learn/fundamentals/modules/page.mdx +++ b/www/apps/book/app/learn/fundamentals/modules/page.mdx @@ -81,7 +81,7 @@ You define a service in a `service.ts` or `service.js` file at the root of your export const highlights = [ ["4", "MedusaService", "The service factory function."], - ["5", "MyCustom", "The data models to generate data-management methods for."] + ["5", "Post", "The data models to generate data-management methods for."] ] ```ts title="src/modules/blog/service.ts" highlights={highlights} diff --git a/www/apps/book/next.config.mjs b/www/apps/book/next.config.mjs index b27ce24cec..0cdc2630ab 100644 --- a/www/apps/book/next.config.mjs +++ b/www/apps/book/next.config.mjs @@ -9,6 +9,7 @@ import { crossProjectLinksPlugin, recmaInjectMdxDataPlugin, remarkAttachFrontmatterDataPlugin, + validateHighlightsPlugin, } from "remark-rehype-plugins" import path from "path" import redirects from "./utils/redirects.mjs" @@ -78,6 +79,7 @@ const withMDX = mdx({ tagName: "code", }, ], + [validateHighlightsPlugin, { verbose: false }], [rehypeSlug], [ cloudinaryImgRehypePlugin, diff --git a/www/apps/cloud/next.config.mjs b/www/apps/cloud/next.config.mjs index 5e6a501c84..b41e84235f 100644 --- a/www/apps/cloud/next.config.mjs +++ b/www/apps/cloud/next.config.mjs @@ -13,6 +13,7 @@ import { prerequisitesLinkFixerPlugin, remarkAttachFrontmatterDataPlugin, recmaInjectMdxDataPlugin, + validateHighlightsPlugin, } from "remark-rehype-plugins" import bundleAnalyzer from "@next/bundle-analyzer" import withExtractedTableOfContents from "@stefanprobst/rehype-extract-toc" @@ -79,6 +80,7 @@ const withMDX = mdx({ tagName: "code", }, ], + [validateHighlightsPlugin, { verbose: false }], [rehypeSlug], [ cloudinaryImgRehypePlugin, diff --git a/www/apps/resources/app/commerce-modules/inventory/inventory-kit/page.mdx b/www/apps/resources/app/commerce-modules/inventory/inventory-kit/page.mdx index 77882f4f1f..25ee3587b7 100644 --- a/www/apps/resources/app/commerce-modules/inventory/inventory-kit/page.mdx +++ b/www/apps/resources/app/commerce-modules/inventory/inventory-kit/page.mdx @@ -229,7 +229,7 @@ Using [workflows](!docs!/learn/fundamentals/workflows), you can implement this b export const bundledHighlights1 = [ ["11", "products", "Create the products part of the bundle."], - ["28", "manage_inventory", "Enabling this without specifying inventory items creates a default inventory item."] + ["29", "manage_inventory", "Enabling this without specifying inventory items creates a default inventory item."] ] ```ts highlights={bundledHighlights1} @@ -390,7 +390,7 @@ Finally, create the bundled product: export const bundledProductHighlights3 = [ ["5", "bundledProduct", "Create the bundled product."], - ["22", "inventory_items", "Pass the inventory items of the products part of the bundle."] + ["23", "inventory_items", "Pass the inventory items of the products part of the bundle."] ] ```ts highlights={bundledProductHighlights3} diff --git a/www/apps/resources/app/examples/guides/quote-management/page.mdx b/www/apps/resources/app/examples/guides/quote-management/page.mdx index 89b5701df1..9ffeba6c90 100644 --- a/www/apps/resources/app/examples/guides/quote-management/page.mdx +++ b/www/apps/resources/app/examples/guides/quote-management/page.mdx @@ -2884,9 +2884,9 @@ Create the file `src/workflows/merchant-send-quote.ts` with the following conten ![Directory structure after adding the merchant send quote workflow file](https://res.cloudinary.com/dza7lstvk/image/upload/v1741162342/Medusa%20Resources/quote-38_n4ksr0.jpg) export const sendQuoteHighlights = [ - ["15", "useQueryGraphStep", "Retrieve the quote's details."], - ["24", "validateQuoteNotAccepted", "Validate that the quote isn't already accepted by the customer."], - ["29", "updateQuotesStep", "Update the quote's status to `pending_customer`."] + ["14", "useQueryGraphStep", "Retrieve the quote's details."], + ["23", "validateQuoteNotAccepted", "Validate that the quote isn't already accepted by the customer."], + ["28", "updateQuotesStep", "Update the quote's status to `pending_customer`."] ] ```ts title="src/workflows/merchant-send-quote.ts" highlights={sendQuoteHighlights} diff --git a/www/apps/resources/app/how-to-tutorials/tutorials/loyalty-points/page.mdx b/www/apps/resources/app/how-to-tutorials/tutorials/loyalty-points/page.mdx index 77513b91ae..2e71932669 100644 --- a/www/apps/resources/app/how-to-tutorials/tutorials/loyalty-points/page.mdx +++ b/www/apps/resources/app/how-to-tutorials/tutorials/loyalty-points/page.mdx @@ -1415,8 +1415,8 @@ To create the workflow, create the file `src/workflows/apply-loyalty-on-cart.ts` export const applyLoyaltyOnCartWorkflowHighlights = [ ["46", "useQueryGraphStep", "Retrieve the cart's details."], ["57", "validateCustomerExistsStep", "Validate that the customer is registered."], - ["59", "getCartLoyaltyPromoStep", "Retrieve the cart's loyalty promotion."], - ["61", "acquireLockStep", "Acquire a lock on the cart to prevent concurrent modifications."], + ["61", "getCartLoyaltyPromoStep", "Retrieve the cart's loyalty promotion."], + ["66", "acquireLockStep", "Acquire a lock on the cart to prevent concurrent modifications."], ["72", "getCartLoyaltyPromoAmountStep", "Get the amount to be discounted based on the loyalty points."], ] diff --git a/www/apps/resources/app/how-to-tutorials/tutorials/phone-auth/page.mdx b/www/apps/resources/app/how-to-tutorials/tutorials/phone-auth/page.mdx index d53e6812f6..28746eb7f2 100644 --- a/www/apps/resources/app/how-to-tutorials/tutorials/phone-auth/page.mdx +++ b/www/apps/resources/app/how-to-tutorials/tutorials/phone-auth/page.mdx @@ -917,11 +917,11 @@ A Notification Module Provider has a service that contains the sending logic. Th So, create the file `src/modules/twilio-sms/service.ts` with the following content: export const twilioSmsServiceHighlights = [ - ["8", "accountSid", "Twilio account SID."], - ["9", "authToken", "Twilio auth token."], - ["10", "from", "Twilio phone number to send the SMS from."], - ["14", "identifier", "Unique identifier for the module."], - ["15", "client", "Twilio client to send the SMS."], + ["9", "accountSid", "Twilio account SID."], + ["10", "authToken", "Twilio auth token."], + ["11", "from", "Twilio phone number to send the SMS from."], + ["15", "identifier", "Unique identifier for the module."], + ["16", "client", "Twilio client to send the SMS."], ] ```ts title="src/modules/twilio-sms/service.ts" highlights={twilioSmsServiceHighlights} diff --git a/www/apps/resources/app/how-to-tutorials/tutorials/preorder/page.mdx b/www/apps/resources/app/how-to-tutorials/tutorials/preorder/page.mdx index 971c3bd3c6..a303c26439 100644 --- a/www/apps/resources/app/how-to-tutorials/tutorials/preorder/page.mdx +++ b/www/apps/resources/app/how-to-tutorials/tutorials/preorder/page.mdx @@ -538,12 +538,12 @@ If you get a type error on resolving the Preorder Module, run the Medusa applica export const updatePreorderVariantStepHighlights = [ - ["16", "preorderModuleService", "Resolve the Preorder Module's service from the Medusa container."], - ["20", "oldData", "Retrieve existing record to undo updates if an error occurs."], - ["24", "preorderVariant", "Update the pre-order variant."], - ["28", "preorderVariant", "Return the updated pre-order variant."], - ["28", "oldData", "Pass the old data to the compensation function."], - ["39", "updatePreorderVariants", "Undo updates if an error occurs during the workflow execution."] + ["17", "preorderModuleService", "Resolve the Preorder Module's service from the Medusa container."], + ["21", "oldData", "Retrieve existing record to undo updates if an error occurs."], + ["25", "preorderVariant", "Update the pre-order variant."], + ["29", "preorderVariant", "Return the updated pre-order variant."], + ["29", "oldData", "Pass the old data to the compensation function."], + ["40", "updatePreorderVariants", "Undo updates if an error occurs during the workflow execution."] ] ```ts title="src/workflows/steps/update-preorder-variant.ts" highlights={updatePreorderVariantStepHighlights} @@ -623,10 +623,10 @@ The `createPreorderVariantStep` creates a pre-order variant record. To create the step, create the file `src/workflows/steps/create-preorder-variant.ts` with the following content: export const createPreorderVariantStepHighlights = [ - ["15", "preorderVariant", "Create the pre-order variant."], - ["19", "preorderVariant", "Return the created pre-order variant."], - ["19", "id", "Pass the ID to the compensation function."], - ["30", "deletePreorderVariants", "Delete the pre-order variant if an error occurs during the workflow execution."] + ["16", "preorderVariant", "Create the pre-order variant."], + ["20", "preorderVariant", "Return the created pre-order variant."], + ["20", "id", "Pass the ID to the compensation function."], + ["31", "deletePreorderVariants", "Delete the pre-order variant if an error occurs during the workflow execution."] ] ```ts title="src/workflows/steps/create-preorder-variant.ts" highlights={createPreorderVariantStepHighlights} @@ -811,7 +811,7 @@ export const upsertPreorderVariantRouteHighlights = [ ["10", "UpsertPreorderVariantSchema", "The schema to validate the request body."], ["18", "POST", "Expose a POST API route."], ["24", "upsertProductVariantPreorderWorkflow", "Execute the workflow to create or update pre-order variant configurations."], - ["32", "preorder_variant", "Return the created or updated pre-order variant in the response."], + ["33", "preorder_variant", "Return the created or updated pre-order variant in the response."], ] ```ts title="src/api/admin/variants/[id]/preorders/route.ts" highlights={upsertPreorderVariantRouteHighlights} @@ -944,12 +944,12 @@ The `disablePreorderVariantStep` changes the status of a pre-order variant recor Create the file `src/workflows/steps/disable-preorder-variant.ts` with the following content: export const disablePreorderVariantStepHighlights = [ - ["15", "oldData", "Retrieve existing record to undo updates if an error occurs."], - ["17", "preorderVariant", "Update the pre-order variant."], - ["19", "DISABLED", "Set the pre-order variant's status to `disabled`."], - ["22", "preorderVariant", "Return the updated pre-order variant."], - ["22", "oldData", "Pass the old data to the compensation function."], - ["31", "updatePreorderVariants", "Undo updates if an error occurs during the workflow execution."] + ["16", "oldData", "Retrieve existing record to undo updates if an error occurs."], + ["18", "preorderVariant", "Update the pre-order variant."], + ["20", "DISABLED", "Set the pre-order variant's status to `disabled`."], + ["23", "preorderVariant", "Return the updated pre-order variant."], + ["23", "oldData", "Pass the old data to the compensation function."], + ["32", "updatePreorderVariants", "Undo updates if an error occurs during the workflow execution."] ] ```ts title="src/workflows/steps/disable-preorder-variant.ts" highlights={disablePreorderVariantStepHighlights} @@ -1688,9 +1688,9 @@ The `createPreordersStep` creates a `Preorder` record for each pre-order variant Create the file `src/workflows/steps/create-preorders.ts` with the following content: export const createPreordersStepHighlights = [ - ["16", "preorders", "Create pre-orders."], - ["23", "preorders", "Return the pre-orders."], - ["32", "deletePreorders", "Delete pre-orders if an error occurs during the workflow execution."], + ["17", "preorders", "Create pre-orders."], + ["24", "preorders", "Return the pre-orders."], + ["33", "deletePreorders", "Delete pre-orders if an error occurs during the workflow execution."], ] ```ts title="src/workflows/steps/create-preorders.ts" highlights={createPreordersStepHighlights} @@ -1927,7 +1927,7 @@ export const validateCartHookHighlights = [ ["32", "variantsToAdd", "Retrieve the pre-order variants of the new items being added to the cart."], ["42", "cartHasPreorderVariants", "Check if the cart has pre-order variants."], ["48", "newItemsHavePreorderVariants", "Check if the new items being added have pre-order variants."], - ["55", "throw MedusaError", "Throw an error if the cart has mixed pre-order and available items."], + ["55", "MedusaError", "Throw an error if the cart has mixed pre-order and available items."], ] ```ts title="src/workflows/hooks/validate-cart.ts" highlights={validateCartHookHighlights} @@ -2759,12 +2759,12 @@ The `updatePreordersStep` updates the details of pre-order records. Create the file `src/workflows/steps/update-preorders.ts` with the following content: export const updatePreordersHighlights = [ - ["13", "preorders", "The pre-orders to update."], - ["16", "oldPreorders", "The pre-orders before the update."], - ["20", "updatedPreorders", "Update the pre-orders."], - ["24", "updatedPreorders", "Return the updated pre-orders."], - ["24", "oldPreorders", "Pass the old pre-orders to the compensation function."], - ["33", "updatePreorders", "Revert the pre-order updates if an error occurs during the workflow's execution."] + ["14", "preorders", "The pre-orders to update."], + ["17", "oldPreorders", "The pre-orders before the update."], + ["21", "updatedPreorders", "Update the pre-orders."], + ["25", "updatedPreorders", "Return the updated pre-orders."], + ["25", "oldPreorders", "Pass the old pre-orders to the compensation function."], + ["34", "updatePreorders", "Revert the pre-order updates if an error occurs during the workflow's execution."] ] ```ts title="src/workflows/steps/update-preorders.ts" highlights={updatePreordersHighlights} @@ -2964,14 +2964,7 @@ export const retrieveItemsToFulfillStep = createStep( Then, update the workflow to the following: -export const fulfillPreorderWorkflowHighlights2 = [ - ["22"], ["23"], ["24"], ["25"], ["37"], ["55"], ["56"], ["57"], ["58"], - ["59"], ["60"], ["61"], ["62"], ["63"], ["64"], ["65"], ["66"], ["67"], - ["68"], ["69"], ["70"], ["71"], ["72"], ["73"], ["74"], ["75"], ["76"], - ["77"], ["78"], ["79"], ["80"], -] - -```ts title="src/workflows/fulfill-preorder.ts" highlights={fulfillPreorderWorkflowHighlights2} +```ts title="src/workflows/fulfill-preorder.ts" import { InferTypeOf } from "@medusajs/framework/types" import { PreorderVariant } from "../modules/preorder/models/preorder-variant" import { createWorkflow, transform, when, WorkflowResponse } from "@medusajs/framework/workflows-sdk" @@ -3135,7 +3128,7 @@ export const fulfillPreordersJobHighlights2 = [ ["24", "available_date", "Retrieve only the pre-order variants available today."], ["43", "unfulfilledPreorders", "The unfulfilled pre-orders retrieved."], ["44", "preorderMetadata", "The pagination details of the pre-order query."], - ["66", "fulfillPreorderWorkflow.run", "Fulfill a pre-order of the variant."], + ["66", "fulfillPreorderWorkflow", "Fulfill a pre-order of the variant."], ] ```ts title="src/jobs/fulfill-preorders.ts" highlights={fulfillPreordersJobHighlights2} @@ -3498,7 +3491,7 @@ export const orderCanceledHighlights = [ ["14", "workflowInput", "Prepare the input to pass to the workflow."], ["24", "preorders", "Retrieve the pre-orders of the order."], ["41", "push", "Add the pre-orders to the workflow input."], - ["46", "cancelPreordersWorkflow.run", "Execute the cancel pre-orders workflow."], + ["46", "cancelPreordersWorkflow", "Execute the cancel pre-orders workflow."], ] ```ts title="src/subscribers/order-canceled.ts" highlights={orderCanceledHighlights} @@ -3642,10 +3635,7 @@ Create the file `src/workflows/steps/retrieve-preorder-updates.ts` with the foll export const retrievePreorderUpdatesStepHighlights = [ ["20", "preordersToCancel", "The pre-orders to cancel."], ["24", "preordersToCreate", "The pre-orders to create."], - ["20", "preorder_variant", "The pre-order variant associated with the item."], - ["32", "", "Find the new pre-order items."], ["44", "push", "Add the pre-order variant to the pre-orders to create."], - ["50", "", "Find the pre-order items that need to be canceled."], ["55", "push", "Add the pre-order to the pre-orders to cancel."], ] diff --git a/www/apps/resources/app/how-to-tutorials/tutorials/product-builder/page.mdx b/www/apps/resources/app/how-to-tutorials/tutorials/product-builder/page.mdx index da5e80df5d..6bd2829301 100644 --- a/www/apps/resources/app/how-to-tutorials/tutorials/product-builder/page.mdx +++ b/www/apps/resources/app/how-to-tutorials/tutorials/product-builder/page.mdx @@ -5540,8 +5540,6 @@ You also need to update the components that use the `Item` component to pass the In `src/modules/cart/templates/items.tsx`, replace the `return` statement with the following: export const itemsTemplateHighlights = [ - ["13", "className"], - ["17", "className"], ["34", "cartItems", "Pass new prop"] ] @@ -5669,12 +5667,7 @@ You calculate the total items by summing the quantities of the `filteredItems`, Finally, in the `return` statement, replace all usages of `cartState.items` with `filteredItems`, and remove the children element of the `DeleteButton` for better styling: -export const cartDropdownHighlights = [ - ["6", "filteredItems"], ["9", "filteredItems"], - ["21"], ["22"], ["23"], ["24"], ["25"] -] - -```tsx title="src/modules/layout/components/cart-dropdown/index.tsx" badgeLabel="Storefront" badgeColor="blue" highlights={cartDropdownHighlights} +```tsx title="src/modules/layout/components/cart-dropdown/index.tsx" badgeLabel="Storefront" badgeColor="blue" highlights={[["6"], ["9"], ["21"], ["22"], ["23"], ["24"], ["25"]]} return (
export const syncStepHighlights = [ - ["13", "createStep", "Create a step."], - ["15", "container", "The Medusa container to resolve resources."], - ["36", "graph", "Retrieve a paginated list of products with their sanity document."] + ["14", "createStep", "Create a step."], + ["16", "container", "The Medusa container to resolve resources."], + ["37", "graph", "Retrieve a paginated list of products with their sanity document."] ] ```ts title="src/workflows/sanity-sync-products/steps/sync.ts" highlights={syncStepHighlights} @@ -1205,7 +1205,7 @@ Now that you're managing a product's content in Sanity, you want to show that co A product's details are retrieved in the file `src/app/[countryCode]/(main)/products/[handle]/page.tsx`. So, replace the `ProductPage` function with the following: export const sanityContentHighlights = [ - ["19", "sanity", "Get the product's content from Sanity."] + ["24", "sanity", "Get the product's content from Sanity."] ] ```tsx title="src/app/[countryCode]/(main)/products/[handle]/page.tsx" badgeLabel="Storefront" badgeColor="blue" highlights={sanityContentHighlights} diff --git a/www/apps/resources/app/integrations/guides/shipstation/page.mdx b/www/apps/resources/app/integrations/guides/shipstation/page.mdx index 87f262a833..9374fdd1ee 100644 --- a/www/apps/resources/app/integrations/guides/shipstation/page.mdx +++ b/www/apps/resources/app/integrations/guides/shipstation/page.mdx @@ -800,10 +800,10 @@ Finally, add the `calculatePrice` method to `ShipStationProviderService`: export const serviceHighlights5 = [ ["14", "shipment_id", "Retrieve the shipping method's shipment ID."], - ["20", "createShipment", "If a shipment isn't already created, create the shipment and get its rates."], - ["23", "getShipmentRates", "If a shipment is already created, retrieve its rates."], - ["27", "calculatedPrice", "Calculate the price from the specified rate."], - ["34", "is_calculated_price_tax_inclusive", "Return whether the price includes taxes."] + ["24", "createShipment", "If a shipment isn't already created, create the shipment and get its rates."], + ["37", "getShipmentRates", "If a shipment is already created, retrieve its rates."], + ["41", "calculatedPrice", "Calculate the price from the specified rate."], + ["47", "is_calculated_price_tax_inclusive", "Return whether the price includes taxes."] ] ```ts title="src/modules/shipstation/service.ts" highlights={serviceHighlights5} @@ -892,8 +892,8 @@ Add the `validateFulfillmentData` method to `ShipStationProviderService`: export const serviceHighlights4 = [ ["8", "shipment_id", "Get the ID of an already created shipment, if available."], - ["14", "createShipment", "Create a shipment if it doesn't already exist."], - ["20", "shipment_id", "Store the shipment ID in the shipping method's `data`."] + ["17", "createShipment", "Create a shipment if it doesn't already exist."], + ["38", "shipment_id", "Store the shipment ID in the shipping method's `data`."] ] ```ts title="src/modules/shipstation/service.ts" highlights={serviceHighlights4} diff --git a/www/apps/resources/app/nextjs-starter/guides/storefront-returns/page.mdx b/www/apps/resources/app/nextjs-starter/guides/storefront-returns/page.mdx index 8e4892dee3..593ef9e9e9 100644 --- a/www/apps/resources/app/nextjs-starter/guides/storefront-returns/page.mdx +++ b/www/apps/resources/app/nextjs-starter/guides/storefront-returns/page.mdx @@ -657,13 +657,13 @@ The component will display the available shipping options for returns, along wit To create the component, create the file `src/modules/account/components/return-shipping-selector/index.tsx` with the following content: export const returnShippingSelectorHighlights = [ - ["13", "shippingOptions", "The available shipping options for returns."], - ["14", "selectedOption", "The currently selected shipping option ID."], - ["15", "onOptionSelect", "Callback function when a shipping option is selected."], - ["16", "cartId", "The ID of the cart associated with the order being returned."], - ["17", "currencyCode", "The currency code for displaying prices."], - ["32", "useEffect", "Fetches calculated prices for shipping options with price type 'calculated'."], - ["58", "", "Renders a message if no shipping options are available."], + ["16", "shippingOptions", "The available shipping options for returns."], + ["17", "selectedOption", "The currently selected shipping option ID."], + ["18", "onOptionSelect", "Callback function when a shipping option is selected."], + ["19", "cartId", "The ID of the cart associated with the order being returned."], + ["20", "currencyCode", "The currency code for displaying prices."], + ["35", "useEffect", "Fetches calculated prices for shipping options with price type 'calculated'."], + ["61", "", "Renders a message if no shipping options are available."], ] ```tsx title="src/modules/account/components/return-shipping-selector/index.tsx" highlights={returnShippingSelectorHighlights} collapsibleLines="1-11" expandButtonLabel="Show Imports" diff --git a/www/apps/resources/app/plugins/guides/wishlist/page.mdx b/www/apps/resources/app/plugins/guides/wishlist/page.mdx index 8dbc66c51a..8d7fd71741 100644 --- a/www/apps/resources/app/plugins/guides/wishlist/page.mdx +++ b/www/apps/resources/app/plugins/guides/wishlist/page.mdx @@ -614,7 +614,7 @@ export const createWishlistStepHighlights = [ ["16", "createWishlists", "Create the wishlist."], ["18", "wishlist", "Return the wishlist"], ["18", "wishlist.id", "Pass the wishlist's ID to the compensation function."], - ["24", "deleteWishlists", "Delete the wishlist if an error occurs in the workflow."] + ["27", "deleteWishlists", "Delete the wishlist if an error occurs in the workflow."] ] ```ts title="src/workflows/steps/create-wishlist.ts" highlights={createWishlistStepHighlights} @@ -1140,7 +1140,7 @@ Create the file `src/workflows/steps/create-wishlist-item.ts` with the following export const createWishlistItemStepHighlights = [ ["16", "createWishlistItems", "Create the wishlist item."], - ["24", "deleteWishlistItems", "Delete the wishlist item if an error occurs in the workflow."] + ["27", "deleteWishlistItems", "Delete the wishlist item if an error occurs in the workflow."] ] ```ts title="src/workflows/steps/create-wishlist-item.ts" highlights={createWishlistItemStepHighlights} diff --git a/www/apps/resources/app/recipes/bundled-products/examples/standard/page.mdx b/www/apps/resources/app/recipes/bundled-products/examples/standard/page.mdx index 7cec297e1d..8652c139b7 100644 --- a/www/apps/resources/app/recipes/bundled-products/examples/standard/page.mdx +++ b/www/apps/resources/app/recipes/bundled-products/examples/standard/page.mdx @@ -1297,8 +1297,8 @@ export const createBundledProductComponentHighlights2 = [ ["3", "currentProductPage", "The current page of products retrieved from the server."], ["4", "productsCount", "The total number of products."], ["5", "hasNextPage", "Whether there are more products to load."], - ["9", "useQuery", "Retrieve the products from the API route."], - ["23", "fetchMoreProducts", "Fetch more products when the user scrolls to the end of the list."], + ["10", "useQuery", "Retrieve the products from the API route."], + ["24", "fetchMoreProducts", "Fetch more products when the user scrolls to the end of the list."], ] ```tsx title="src/admin/components/create-bundled-product.tsx" highlights={createBundledProductComponentHighlights2} @@ -1799,7 +1799,7 @@ export const prepareBundleCartDataStepHighlights = [ ["12", "bundle", "The bundle to add to the cart."], ["15", "quantity", "The quantity of the bundle to add to the cart."], ["16", "items", "The selected variants for each item in the bundle."], - ["15", "bundleItems", "Prepare the items to be added to the cart."], + ["25", "bundleItems", "Prepare the items to be added to the cart."], ["45", "variant_id", "The ID of the selected variant to add to the cart."], ["46", "quantity", "The quantity of the variant to add to the cart."], ["47", "metadata", "The metadata for the line item in the cart."], diff --git a/www/apps/resources/app/recipes/digital-products/examples/standard/page.mdx b/www/apps/resources/app/recipes/digital-products/examples/standard/page.mdx index be1b01dd4b..7a0fa9b9fc 100644 --- a/www/apps/resources/app/recipes/digital-products/examples/standard/page.mdx +++ b/www/apps/resources/app/recipes/digital-products/examples/standard/page.mdx @@ -1887,9 +1887,9 @@ Create the file `src/workflows/create-digital-product-order/steps/create-digital export const createDpoHighlights = [ ["18", "InferTypeOf", "Infer the type of the `DigitalProduct` data model since it's a variable."], - ["33", "createDigitalProductOrders", "Create the digital product order."], - ["41", "digital_product_order", "Pass the created digital product order to the compensation function."], - ["51", "deleteDigitalProductOrders", "Delete the digital product order if an error occurs in the workflow."] + ["32", "createDigitalProductOrders", "Create the digital product order."], + ["40", "digital_product_order", "Pass the created digital product order to the compensation function."], + ["50", "deleteDigitalProductOrders", "Delete the digital product order if an error occurs in the workflow."] ] ```ts title="src/workflows/create-digital-product-order/steps/create-digital-product-order.ts" highlights={createDpoHighlights} collapsibleLines="1-14" expandMoreLabel="Show Imports" @@ -2653,10 +2653,10 @@ Create the file `src/api/store/customers/me/digital-products/[mediaId]/download/ export const downloadUrlHighlights = [ ["20", "query.graph", "Get the customer's orders and linked digital orders."], - ["36", "query.graph", "Get the digital product orders of the customer and associated products and media."], - ["56", "foundMedia", "Set `foundMedia` if the media's ID is equal to the ID passed as a route parameter."], - ["65", "!foundMedia", "If `foundMedia` isn't set, throw an error."], - ["72", "retrieveFile", "Retrieve the details of the media's file."] + ["34", "query.graph", "Get the digital product orders of the customer and associated products and media."], + ["55", "foundMedia", "Set `foundMedia` if the media's ID is equal to the ID passed as a route parameter."], + ["61", "!foundMedia", "If `foundMedia` isn't set, throw an error."], + ["68", "retrieveFile", "Retrieve the details of the media's file."] ] ```ts title="src/api/store/customers/me/digital-products/[mediaId]/download/route.ts" highlights={downloadUrlHighlights} collapsibleLines="1-10" expandMoreLabel="Show Imports" diff --git a/www/apps/resources/app/recipes/marketplace/examples/restaurant-delivery/page.mdx b/www/apps/resources/app/recipes/marketplace/examples/restaurant-delivery/page.mdx index 81aa15253a..816fef337d 100644 --- a/www/apps/resources/app/recipes/marketplace/examples/restaurant-delivery/page.mdx +++ b/www/apps/resources/app/recipes/marketplace/examples/restaurant-delivery/page.mdx @@ -1751,7 +1751,7 @@ Create the file `src/workflows/delivery/steps/notify-restaurant.ts` with the fol export const notifyRestaurantStepHighlights = [ ["11", "async", "Set the step as async."], ["18", "graph", "Retrieve the delivery and its restaurant."], - ["30", "emit", "Emit a custom event that can be used to notify the restaurant that a new delivery is created."] + ["28", "emit", "Emit a custom event that can be used to notify the restaurant that a new delivery is created."] ] ```ts title="src/workflows/delivery/steps/notify-restaurant.ts" highlights={notifyRestaurantStepHighlights} collapsibleLines="1-6" expandButtonLabel="Show Imports" @@ -1835,7 +1835,7 @@ This step is async and its only purpose is to wait until it’s marked as succes Create the file `src/workflows/delivery/steps/create-order.ts` with the following content: export const createOrderStepHighlights1 = [ - ["16", "deliveryQuery", "Retrieve the delivery with its linked cart's details."] + ["15", "delivery", "Retrieve the delivery with its linked cart's details."] ] ```ts title="src/workflows/delivery/steps/create-order.ts" highlights={createOrderStepHighlights1} collapsibleLines="1-9" expandButtonLabel="Show Imports" diff --git a/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx b/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx index 515830e831..6ddc3982c1 100644 --- a/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx +++ b/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx @@ -585,11 +585,11 @@ You can now create the workflow that creates a vendor and its admin. Create the file `src/workflows/marketplace/create-vendor/index.ts` with the following content: export const vendorWorkflowHighlights = [ - ["27", "createVendorStep", "Create the vendor."], - ["33", "transform", "Prepare the vendor admin's data."], - ["43", "createVendorAdminStep", "Create the vendor admin."], - ["47", "setAuthAppMetadataStep", "Create the `vendor` actor type."], - ["53", "useQueryGraphStep", "Retrieve the created vendor with its admins."], + ["28", "createVendorStep", "Create the vendor."], + ["34", "transform", "Prepare the vendor admin's data."], + ["44", "createVendorAdminStep", "Create the vendor admin."], + ["48", "setAuthAppMetadataStep", "Create the `vendor` actor type."], + ["54", "useQueryGraphStep", "Retrieve the created vendor with its admins."], ] ```ts title="src/workflows/marketplace/create-vendor/index.ts" highlights={vendorWorkflowHighlights} @@ -1542,7 +1542,6 @@ export const vendorOrder3Highlights = [ ["3", "map", "Loop over the vendor IDs and create a child order with only their items."], ["11", "prepareOrderData", "Format the order data and pass it as the workflow's input."], ["18", "push", "Add a link between the vendor and the order to be created later."], - ["30", "cancelOrderWorkflow", "Cancel all created workflows if an error occurs while creating any of them."] ] ```ts title="src/workflows/marketplace/create-vendor-orders/steps/create-vendor-orders.ts" highlights={vendorOrder3Highlights} diff --git a/www/apps/resources/app/recipes/subscriptions/examples/standard/page.mdx b/www/apps/resources/app/recipes/subscriptions/examples/standard/page.mdx index 7aa7a1eeac..810c5a0fe4 100644 --- a/www/apps/resources/app/recipes/subscriptions/examples/standard/page.mdx +++ b/www/apps/resources/app/recipes/subscriptions/examples/standard/page.mdx @@ -722,10 +722,14 @@ The compensation function receives the subscription as a parameter. It cancels t Create the file `src/workflows/create-subscription/index.ts` with the following content: export const createSubscriptionWorkflowHighlights = [ - ["26", "completeCartWorkflow", "Complete the cart and create the order."], - ["32", "useQueryGraphStep", "Retrieve the order's details."], - ["87", "createSubscriptionStep", "Create the subscription."], - ["94", "createRemoteLinkStep", "Create the links returned by the previous step."] + ["29", "acquireLockStep", "Acquire a lock on the cart to prevent race conditions."], + ["34", "completeCartWorkflow", "Complete the cart and create the order."], + ["40", "useQueryGraphStep", "Retrieve the order's details."], + ["95", "useQueryGraphStep", "Retrieve any existing subscription links for the order."], + ["101", "when", "Check if a subscription already exists for the order."], + ["108", "createSubscriptionStep", "Create the subscription."], + ["115", "createRemoteLinkStep", "Create the links returned by the previous step."], + ["120", "releaseLockStep", "Release the lock on the cart."] ] ```ts title="src/workflows/create-subscription/index.ts" highlights={createSubscriptionWorkflowHighlights} collapsibleLines="1-13" expandMoreLabel="Show Imports" diff --git a/www/apps/resources/app/recipes/ticket-booking/example/storefront/page.mdx b/www/apps/resources/app/recipes/ticket-booking/example/storefront/page.mdx index 3a9d233499..74e8d6795c 100644 --- a/www/apps/resources/app/recipes/ticket-booking/example/storefront/page.mdx +++ b/www/apps/resources/app/recipes/ticket-booking/example/storefront/page.mdx @@ -1212,13 +1212,7 @@ This displays the selected seat number and show date for ticket products instead You should also remove the quantity selector for ticket products since you can't purchase multiple tickets for the same seat. Remove the following highlighted lines from the `return` statement of the `Item` component: -export const removeHighlights = [ - ["5"], ["6"], ["7"], ["8"], ["9"], ["10"], ["11"], ["12"], ["13"], ["14"], - ["15"], ["16"], ["17"], ["18"], ["19"], ["20"], ["21"], ["22"], ["23"], ["24"], - ["25"], ["26"], ["27"], ["29"] -] - -```tsx title="src/modules/cart/components/item/index.tsx" highlights={removeHighlights} +```tsx title="src/modules/cart/components/item/index.tsx" {type === "full" && (
diff --git a/www/apps/resources/app/storefront-development/cart/retrieve/page.mdx b/www/apps/resources/app/storefront-development/cart/retrieve/page.mdx index 40e5b3a8af..fba06e5d05 100644 --- a/www/apps/resources/app/storefront-development/cart/retrieve/page.mdx +++ b/www/apps/resources/app/storefront-development/cart/retrieve/page.mdx @@ -26,7 +26,6 @@ For example: export const highlights = [ ["17", "cartId", "Retrieve the cart ID from `localStorage`."], ["19", "TODO", "You can create the cart and set it here as explained in the Create Cart guide."], - ["23"], ["24"], ["25"], ["26"], ["29", "formatPrice", "This function was previously created to format product prices. You can re-use the same function."], ["32", "currency", "If you reuse the `formatPrice` function, pass the currency code as a parameter."], ] diff --git a/www/apps/resources/app/storefront-development/checkout/address/page.mdx b/www/apps/resources/app/storefront-development/checkout/address/page.mdx index e222b8c6d0..2059b99c1a 100644 --- a/www/apps/resources/app/storefront-development/checkout/address/page.mdx +++ b/www/apps/resources/app/storefront-development/checkout/address/page.mdx @@ -50,8 +50,6 @@ For example: export const highlights = [ ["4", "useCart", "The `useCart` hook was defined in the Cart React Context documentation."], ["30", "address", "Assemble the address object to be used for both shipping and billing addresses."], - ["42"], ["43"], ["44"], ["45"], ["46"], ["47"], ["48"], - ["49"], ["50"], ["96", "", "The address's country can only be within the cart's region."] ] diff --git a/www/apps/resources/app/storefront-development/checkout/email/page.mdx b/www/apps/resources/app/storefront-development/checkout/email/page.mdx index b18dcd6a6f..0f0c2e8919 100644 --- a/www/apps/resources/app/storefront-development/checkout/email/page.mdx +++ b/www/apps/resources/app/storefront-development/checkout/email/page.mdx @@ -39,7 +39,6 @@ For example: export const highlights = [ ["4", "useCart", "The `useCart` hook was defined in the Cart React Context documentation."], ["14", "TODO", "Cart must have at least one item. If not, redirect to another page."], - ["28"], ["29"], ["30"], ["31"], ["32"], ["33"], ["34"], ] ```tsx highlights={highlights} diff --git a/www/apps/resources/app/storefront-development/checkout/shipping/page.mdx b/www/apps/resources/app/storefront-development/checkout/shipping/page.mdx index 60d46ce77b..2a32950c60 100644 --- a/www/apps/resources/app/storefront-development/checkout/shipping/page.mdx +++ b/www/apps/resources/app/storefront-development/checkout/shipping/page.mdx @@ -200,12 +200,12 @@ export const highlights = [ export const fetchHighlights = [ ["5", "retrieveShippingOptions", "This function retrieves the shipping options of the customer's cart."], - ["21", "calculateShippingOptionPrices", "This function retrieves the prices of shipping options of type `calculated`."], - ["34", "data", "Pass in this property any data relevant to the fulfillment provider."], - ["56", "formatPrice", "This function formats a price based on the cart's currency."], - ["65", "getShippingOptionPrice", "This function gets the price of a shipping option based on its type."], - ["77", "setShippingMethod", "This function sets the shipping method of the cart using the selected shipping option."], - ["91", "data", "Pass in this property any data relevant to the fulfillment provider."], + ["13", "calculateShippingOptionPrices", "This function retrieves the prices of shipping options of type `calculated`."], + ["19", "data", "Pass in this property any data relevant to the fulfillment provider."], + ["39", "formatPrice", "This function formats a price based on the cart's currency."], + ["48", "getShippingOptionPrice", "This function gets the price of a shipping option based on its type."], + ["60", "setShippingMethod", "This function sets the shipping method of the cart using the selected shipping option."], + ["65", "data", "Pass in this property any data relevant to the fulfillment provider."], ] ```ts highlights={fetchHighlights} diff --git a/www/apps/resources/app/storefront-development/customers/addresses/page.mdx b/www/apps/resources/app/storefront-development/customers/addresses/page.mdx index f0570360e8..b00e04cdd1 100644 --- a/www/apps/resources/app/storefront-development/customers/addresses/page.mdx +++ b/www/apps/resources/app/storefront-development/customers/addresses/page.mdx @@ -161,8 +161,6 @@ To add a new address for the customer, send a request to the [Add Customer Addre export const addHighlights = [ ["4", "useRegion", "Use the hook defined in the Region Context guide."], ["5", "useCustomer", "Use the hook defined in the Customer Context guide."], - ["29"], ["30"], ["31"], ["32"], ["33"], ["34"], ["35"], ["36"], ["37"], - ["38"], ["39"], ["40"], ["41"], ["42"], ["43"], ] ```tsx highlights={addHighlights} collapsibleLines="46-117" expandButtonLabel="Show form" @@ -334,8 +332,6 @@ export const editHighlights = [ ["4", "useRegion", "Use the hook defined in the Region Context guide."], ["5", "useCustomer", "Use the hook defined in the Customer Context guide."], ["18", "address", "Retrieve the address from the customer's `addresses` property."], - ["59"], ["60"], ["61"], ["62"], ["63"], ["64"], ["65"], ["66"], ["67"], - ["68"], ["69"], ["70"], ["71"], ["72"], ["73"], ] ```tsx highlights={editHighlights} collapsibleLines="76-147" expandButtonLabel="Show form" diff --git a/www/apps/resources/app/storefront-development/customers/login/page.mdx b/www/apps/resources/app/storefront-development/customers/login/page.mdx index 263aa80b14..4986eb63bd 100644 --- a/www/apps/resources/app/storefront-development/customers/login/page.mdx +++ b/www/apps/resources/app/storefront-development/customers/login/page.mdx @@ -292,7 +292,7 @@ curl '{backend_url}/store/products' \ -```ts highlights={["2", "", "Passes the cookie session ID in your request."]} +```ts highlights={[["2", "credentials", "Passes the cookie session ID in your request."]]} fetch(`/store/products`, { credentials: "include", }) diff --git a/www/apps/resources/app/storefront-development/customers/profile/page.mdx b/www/apps/resources/app/storefront-development/customers/profile/page.mdx index 0a38616510..f87b793b26 100644 --- a/www/apps/resources/app/storefront-development/customers/profile/page.mdx +++ b/www/apps/resources/app/storefront-development/customers/profile/page.mdx @@ -33,7 +33,6 @@ For example: export const highlights = [ ["4", "useCustomer", "Use the hook defined in the Customer Context guide."], - ["35"], ["36"], ["37"], ["38"], ["39"], ["40"], ["41"], ["42"], ["43"], ["44"], ] ```tsx highlights={highlights} collapsibleLines="47-85" expandButtonLabel="Show form" diff --git a/www/apps/resources/app/storefront-development/guides/express-checkout/page.mdx b/www/apps/resources/app/storefront-development/guides/express-checkout/page.mdx index 66bb5577ef..c3833519dc 100644 --- a/www/apps/resources/app/storefront-development/guides/express-checkout/page.mdx +++ b/www/apps/resources/app/storefront-development/guides/express-checkout/page.mdx @@ -1350,7 +1350,7 @@ Then, replace the `TODO` in the `Product` component with the following: export const productHighlights4 = [ ["1", "price", "The formatted price to show to the customer."], ["2", "selectedVariantPrice", "Determine the variant to show its price, which is either the selected variant or the variant with the smallest price."], - ["29", "formatPrice", "Return the formatted price using the utility you created."] + ["19", "formatPrice", "Return the formatted price using the utility you created."] ] ```tsx title="components/Product/index.tsx" highlights={productHighlights4} @@ -2049,7 +2049,7 @@ export const shippingHighlights3 = [ ["7", "filter", "Retrieve shipping options with calculated prices only."], ["9", "fetch", "Retrieve the calculated price from the Medusa application."], ["24", "Promise.allSettled", "Wait for all calculated prices to be retrieved."], - ["13", "setCalculatedPrices", "Set the calculated prices in the state variable."], + ["33", "setCalculatedPrices", "Set the calculated prices in the state variable."], ] ```tsx title="components/Shipping/index.tsx" highlights={shippingHighlights3} diff --git a/www/apps/resources/app/storefront-development/localization/page.mdx b/www/apps/resources/app/storefront-development/localization/page.mdx index 1762d7cf03..b9b1b2b703 100644 --- a/www/apps/resources/app/storefront-development/localization/page.mdx +++ b/www/apps/resources/app/storefront-development/localization/page.mdx @@ -50,11 +50,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["18"], ["19"], ["20"], ["21"], ["22"] -] - - ```tsx highlights={highlights} + ```tsx highlights={[["18"], ["19"], ["20"], ["21"], ["22"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/products/categories/list/page.mdx b/www/apps/resources/app/storefront-development/products/categories/list/page.mdx index 91ba37357f..3719798107 100644 --- a/www/apps/resources/app/storefront-development/products/categories/list/page.mdx +++ b/www/apps/resources/app/storefront-development/products/categories/list/page.mdx @@ -36,12 +36,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["18"], ["19"], ["20"], - ["21"], ["22"], -] - - ```tsx highlights={highlights} + ```tsx highlights={[["18"], ["19"], ["20"], ["21"], ["22"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/products/categories/nested-categories/page.mdx b/www/apps/resources/app/storefront-development/products/categories/nested-categories/page.mdx index ebc63fe4d8..54a3daf7fc 100644 --- a/www/apps/resources/app/storefront-development/products/categories/nested-categories/page.mdx +++ b/www/apps/resources/app/storefront-development/products/categories/nested-categories/page.mdx @@ -48,9 +48,8 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. export const highlights = [ - ["22"], ["23", `fields`, "Select the fields of category children"], + ["23", `fields`, "Select the fields of category children"], ["24", "include_descendants_tree", "Indicate that all nested categories should be retrieved."], - ["25"], ["26"], ["27"], ["28"], ["29"], ["39", "category_children", "Show the nested categories."], ] @@ -156,11 +155,9 @@ For example: export const categoriesHighlights = [ - ["22"], ["23"], ["24", `fields`, "Select the fields of category children"], + ["24", `fields`, "Select the fields of category children"], ["25", "include_descendants_tree", "Indicate that all nested categories should be retrieved."], ["26", "parent_category_id", "Since each category will have its children, you only retrieve categories that don't have a parent."], - ["27"], ["28"], - ["29"], ["30"], ["31"], ["45", "category_children", "Show the nested categories."], ] diff --git a/www/apps/resources/app/storefront-development/products/categories/products/page.mdx b/www/apps/resources/app/storefront-development/products/categories/products/page.mdx index a295f739ab..0b7d6e84de 100644 --- a/www/apps/resources/app/storefront-development/products/categories/products/page.mdx +++ b/www/apps/resources/app/storefront-development/products/categories/products/page.mdx @@ -31,10 +31,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. export const highlights = [ - ["29"], ["30"], ["31"], - ["32", "category_id", "Pass the category ID as a query parameter."], ["33"], - ["34"], ["35"], ["36"], - ["37"], ["38"], ["39"], ["40"], ["41"], ["42"], ["43"], ["44"] + ["32", "category_id", "Pass the category ID as a query parameter."], ] ```tsx highlights={highlights} diff --git a/www/apps/resources/app/storefront-development/products/categories/retrieve/page.mdx b/www/apps/resources/app/storefront-development/products/categories/retrieve/page.mdx index 487afe2f9a..c5964edd1d 100644 --- a/www/apps/resources/app/storefront-development/products/categories/retrieve/page.mdx +++ b/www/apps/resources/app/storefront-development/products/categories/retrieve/page.mdx @@ -39,12 +39,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["22"], ["23"], ["24"], - ["25"], ["26"], -] - - ```tsx highlights={highlights} + ```tsx highlights={[["22"], ["23"], ["24"], ["25"], ["26"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" @@ -118,13 +113,7 @@ To retrieve a product by its handle, send a request to the [List Product Categor -export const handleHighlights = [ - ["22"], ["23"], ["24"], - ["25"], ["26"], ["27"], ["28"], - ["29"], ["30"], -] - - ```tsx highlights={handleHighlights} + ```tsx highlights={[["22"], ["23"], ["24"], ["25"], ["26"], ["27"], ["28"], ["29"], ["30"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/products/collections/list/page.mdx b/www/apps/resources/app/storefront-development/products/collections/list/page.mdx index 70e69a872d..55ac378c1b 100644 --- a/www/apps/resources/app/storefront-development/products/collections/list/page.mdx +++ b/www/apps/resources/app/storefront-development/products/collections/list/page.mdx @@ -36,12 +36,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["18"], ["19"], ["20"], - ["21"], ["22"], -] - - ```tsx highlights={highlights} + ```tsx highlights={[["18"], ["19"], ["20"], ["21"], ["22"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/products/collections/products/page.mdx b/www/apps/resources/app/storefront-development/products/collections/products/page.mdx index 595c45e0cb..d6584467e3 100644 --- a/www/apps/resources/app/storefront-development/products/collections/products/page.mdx +++ b/www/apps/resources/app/storefront-development/products/collections/products/page.mdx @@ -31,10 +31,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. export const highlights = [ - ["29"], ["30"], ["31"], - ["32", "collection_id", "Pass the collection ID as a query parameter."], ["33"], - ["34"], ["35"], ["36"], - ["37"], ["38"], ["39"], ["40"], ["41"], ["42"], ["43"], ["44"], ["45"], ["46"], ["47"] + ["32", "collection_id", "Pass the collection ID as a query parameter."], ] ```tsx highlights={highlights} diff --git a/www/apps/resources/app/storefront-development/products/collections/retrieve/page.mdx b/www/apps/resources/app/storefront-development/products/collections/retrieve/page.mdx index 6764d434ee..fedff071c2 100644 --- a/www/apps/resources/app/storefront-development/products/collections/retrieve/page.mdx +++ b/www/apps/resources/app/storefront-development/products/collections/retrieve/page.mdx @@ -39,12 +39,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["22"], ["23"], ["24"], - ["25"], ["26"], -] - - ```tsx highlights={highlights} + ```tsx highlights={[["22"], ["23"], ["24"], ["25"], ["26"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" @@ -117,12 +112,7 @@ To retrieve a product by its handle, send a request to the [List Product Collect -export const handleHighlights = [ - ["24"], ["25"], ["26"], - ["27"], ["28"], ["29"], ["30"], ["31"], ["32"], -] - - ```tsx highlights={handleHighlights} + ```tsx highlights={[["24"], ["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"], ["32"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/products/list/page.mdx b/www/apps/resources/app/storefront-development/products/list/page.mdx index 0e24951e55..a46b762492 100644 --- a/www/apps/resources/app/storefront-development/products/list/page.mdx +++ b/www/apps/resources/app/storefront-development/products/list/page.mdx @@ -29,11 +29,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["18"], ["19"], ["20"], ["21"], ["22"] -] - - ```tsx highlights={highlights} + ```tsx highlights={[["18"], ["19"], ["20"], ["21"], ["22"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/products/retrieve/page.mdx b/www/apps/resources/app/storefront-development/products/retrieve/page.mdx index 808f341c38..8876334574 100644 --- a/www/apps/resources/app/storefront-development/products/retrieve/page.mdx +++ b/www/apps/resources/app/storefront-development/products/retrieve/page.mdx @@ -38,12 +38,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["22"], ["23"], - ["24"], ["25"], ["26"], ["27"], -] - - ```tsx highlights={highlights} + ```tsx highlights={[["22"], ["23"], ["24"], ["25"], ["26"], ["27"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" @@ -137,11 +132,7 @@ To retrieve a product by its handle, send a request to the [List Products API ro -export const handleHighlights = [ - ["24"], ["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"], ["32"] -] - - ```tsx highlights={handleHighlights} + ```tsx highlights={[["24"], ["25"], ["26"], ["27"], ["28"], ["29"], ["30"], ["31"], ["32"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/app/storefront-development/regions/context/page.mdx b/www/apps/resources/app/storefront-development/regions/context/page.mdx index 0a068f6bcb..40157a735f 100644 --- a/www/apps/resources/app/storefront-development/regions/context/page.mdx +++ b/www/apps/resources/app/storefront-development/regions/context/page.mdx @@ -48,7 +48,7 @@ export const highlights = [ ["38", "regionId", "Retrieve the selected region from the `localStorage`."], ["41", "list", "If no region is selected, retrieve the list of regions from the Medusa application and select the first one."], ["47", "retrieve", "If a region is selected, retrieve it from the Medusa application."], - ["6", "useRegion", "The hook that child components of the provider use to access the region."] + ["64", "useRegion", "The hook that child components of the provider use to access the region."] ] ```tsx highlights={highlights} diff --git a/www/apps/resources/app/storefront-development/regions/list/page.mdx b/www/apps/resources/app/storefront-development/regions/list/page.mdx index d921fd8d2d..5c416872a2 100644 --- a/www/apps/resources/app/storefront-development/regions/list/page.mdx +++ b/www/apps/resources/app/storefront-development/regions/list/page.mdx @@ -33,11 +33,7 @@ Learn how to install and configure the JS SDK in the [JS SDK documentation](../. -export const highlights = [ - ["18"], ["19"], ["20"], ["21"], ["22"] -] - - ```tsx highlights={highlights} + ```tsx highlights={[["18"], ["19"], ["20"], ["21"], ["22"]]} "use client" // include with Next.js 13+ import { useEffect, useState } from "react" diff --git a/www/apps/resources/next.config.mjs b/www/apps/resources/next.config.mjs index 63cae9f50e..e606e2b238 100644 --- a/www/apps/resources/next.config.mjs +++ b/www/apps/resources/next.config.mjs @@ -4,6 +4,7 @@ import { prerequisitesLinkFixerPlugin, recmaInjectMdxDataPlugin, typeListLinkFixerPlugin, + validateHighlightsPlugin, workflowDiagramLinkFixerPlugin, } from "remark-rehype-plugins" @@ -48,6 +49,7 @@ const withMDX = mdx({ }, ], ...mdxPluginOptions.options.rehypePlugins, + [validateHighlightsPlugin, { verbose: false }], [localLinksRehypePlugin], [typeListLinkFixerPlugin], [ diff --git a/www/apps/ui/next.config.mjs b/www/apps/ui/next.config.mjs index 8d877116b9..2dc8d8266f 100644 --- a/www/apps/ui/next.config.mjs +++ b/www/apps/ui/next.config.mjs @@ -13,6 +13,7 @@ import { prerequisitesLinkFixerPlugin, remarkAttachFrontmatterDataPlugin, recmaInjectMdxDataPlugin, + validateHighlightsPlugin, uiRehypePlugin, } from "remark-rehype-plugins" import bundleAnalyzer from "@next/bundle-analyzer" @@ -81,6 +82,7 @@ const withMDX = mdx({ tagName: "code", }, ], + [validateHighlightsPlugin, { verbose: false }], [rehypeSlug], [ cloudinaryImgRehypePlugin, diff --git a/www/apps/user-guide/next.config.mjs b/www/apps/user-guide/next.config.mjs index 6d78898760..0bfc5b1c59 100644 --- a/www/apps/user-guide/next.config.mjs +++ b/www/apps/user-guide/next.config.mjs @@ -13,6 +13,7 @@ import { prerequisitesLinkFixerPlugin, remarkAttachFrontmatterDataPlugin, recmaInjectMdxDataPlugin, + validateHighlightsPlugin, } from "remark-rehype-plugins" import bundleAnalyzer from "@next/bundle-analyzer" import withExtractedTableOfContents from "@stefanprobst/rehype-extract-toc" @@ -79,6 +80,7 @@ const withMDX = mdx({ tagName: "code", }, ], + [validateHighlightsPlugin, { verbose: false }], [rehypeSlug], [ cloudinaryImgRehypePlugin, diff --git a/www/packages/docs-utils/src/estree-to-js.ts b/www/packages/docs-utils/src/estree-to-js.ts index dcc66f47e2..e5f38cbefe 100644 --- a/www/packages/docs-utils/src/estree-to-js.ts +++ b/www/packages/docs-utils/src/estree-to-js.ts @@ -9,24 +9,39 @@ import { JSXTextExpression, LiteralExpression, ObjectExpression, + TemplateLiteralExpression, + VariableDeclaration, } from "types" +const ALLOWED_BODY_TYPES = ["ExpressionStatement", "ExportNamedDeclaration"] + export function estreeToJs(estree: Estree) { // TODO improve on this utility. Currently it's implemented to work // for specific use cases as we don't have a lot of info on other // use cases. if ( !estree.body?.length || - estree.body[0].type !== "ExpressionStatement" || - !estree.body[0].expression + !estree.body[0].type || + !ALLOWED_BODY_TYPES.includes(estree.body[0].type) ) { return } - return expressionToJs(estree.body[0].expression) + switch (estree.body[0].type) { + case "ExpressionStatement": + if (!estree.body[0].expression) { + return + } + return expressionToJs(estree.body[0].expression) + case "ExportNamedDeclaration": + if (!estree.body[0].declaration) { + return + } + return declarationToJs(estree.body[0].declaration) + } } -function expressionToJs( +export function expressionToJs( expression: Expression ): ExpressionJsVar | ExpressionJsVar[] | undefined { switch (expression.type) { @@ -84,5 +99,36 @@ function expressionToJs( }, data: text, } + case "TemplateLiteral": + const templateExpression = expression as TemplateLiteralExpression + let value = "" + let raw = "" + templateExpression.quasis.forEach((quasi) => { + value += quasi.value.cooked + raw += quasi.value.raw + }) + return { + original: { + type: "Literal", + value, + raw, + }, + data: value, + } + } +} + +function declarationToJs(declaration: VariableDeclaration): { + name: string + value: ExpressionJsVar | ExpressionJsVar[] | undefined +} { + if (!declaration.declarations.length) { + throw new Error("No declarations found") + } + const name = declaration.declarations[0].id.name + const value = expressionToJs(declaration.declarations[0].init) + return { + name, + value, } } diff --git a/www/packages/remark-rehype-plugins/src/broken-link-checker.ts b/www/packages/remark-rehype-plugins/src/broken-link-checker.ts index 9d13278c2d..f69178aad6 100644 --- a/www/packages/remark-rehype-plugins/src/broken-link-checker.ts +++ b/www/packages/remark-rehype-plugins/src/broken-link-checker.ts @@ -175,7 +175,7 @@ function componentChecker({ const itemJsVar = estreeToJs(attribute.value.data.estree) - if (!itemJsVar) { + if (!itemJsVar || "name" in itemJsVar) { return } @@ -217,7 +217,7 @@ function checkLink({ currentPageFilePath: string options: BrokenLinkCheckerOptions }) { - if (!link || typeof link !== "string") { + if (!link || typeof link !== "string" || link === "/" || link === "#") { return } // try to remove hash diff --git a/www/packages/remark-rehype-plugins/src/cross-project-links.ts b/www/packages/remark-rehype-plugins/src/cross-project-links.ts index bbaa6ec7c1..6dda210549 100644 --- a/www/packages/remark-rehype-plugins/src/cross-project-links.ts +++ b/www/packages/remark-rehype-plugins/src/cross-project-links.ts @@ -88,7 +88,7 @@ function componentFixer( const itemJsVar = estreeToJs(attribute.value.data.estree) - if (!itemJsVar) { + if (!itemJsVar || "name" in itemJsVar) { return } diff --git a/www/packages/remark-rehype-plugins/src/index.ts b/www/packages/remark-rehype-plugins/src/index.ts index 7aa03fd846..cd58f3ccd6 100644 --- a/www/packages/remark-rehype-plugins/src/index.ts +++ b/www/packages/remark-rehype-plugins/src/index.ts @@ -11,6 +11,7 @@ export * from "./prerequisites-link-fixer.js" export * from "./resolve-admonitions.js" export * from "./type-list-link-fixer.js" export * from "./ui-rehype-plugin.js" +export * from "./validate-highlights.js" export * from "./workflow-diagram-link-fixer.js" export * from "./utils/fix-link.js" diff --git a/www/packages/remark-rehype-plugins/src/utils/component-link-fixer.ts b/www/packages/remark-rehype-plugins/src/utils/component-link-fixer.ts index be908e3e7b..f8b773805c 100644 --- a/www/packages/remark-rehype-plugins/src/utils/component-link-fixer.ts +++ b/www/packages/remark-rehype-plugins/src/utils/component-link-fixer.ts @@ -105,7 +105,7 @@ export function componentLinkFixer( const itemJsVar = estreeToJs(attribute.value.data.estree) - if (!itemJsVar) { + if (!itemJsVar || "name" in itemJsVar) { return } diff --git a/www/packages/remark-rehype-plugins/src/validate-highlights.ts b/www/packages/remark-rehype-plugins/src/validate-highlights.ts new file mode 100644 index 0000000000..b1111d307c --- /dev/null +++ b/www/packages/remark-rehype-plugins/src/validate-highlights.ts @@ -0,0 +1,253 @@ +import { + ArrayExpression, + Estree, + ExpressionJsVar, + Identifier, + JSXElementExpression, + JSXExpressionContainer, + LiteralExpression, + UnistNode, + UnistTree, +} from "types" +import type { Transformer } from "unified" +import { estreeToJs, expressionToJs } from "docs-utils" + +type Options = { + verbose?: boolean +} + +export function validateHighlightsPlugin(options?: Options): Transformer { + const { verbose } = options || {} + return async (tree) => { + const { visit } = await import("unist-util-visit") + const highlightConsts = new Map() + + visit(tree as UnistTree, ["mdxjsEsm", "element"], (node: UnistNode) => { + if (node.type === "mdxjsEsm") { + if (node.data && "estree" in node.data && node.data.estree) { + const highlightsJsVar = estreeToJs(node.data.estree) + + if ( + !highlightsJsVar || + !("name" in highlightsJsVar) || + typeof highlightsJsVar.name !== "string" || + !Array.isArray(highlightsJsVar.value) + ) { + return + } + + const highlights = getHighlightsFromExpressionJsVar( + highlightsJsVar.value + ) + if (highlights) { + highlightConsts.set(highlightsJsVar.name, highlights) + } + } + return + } + + if ( + node.tagName !== "pre" || + !node.children?.length || + !node.children[0].data || + !("estree" in node.children[0].data) || + !node.children[0].data.estree + ) { + return + } + + const body = (node.children[0].data.estree as Estree).body?.[0] + + if ( + !body || + body.type !== "ExpressionStatement" || + !body.expression || + body.expression.type !== "JSXElement" + ) { + return + } + + const bodyExpression = body.expression as JSXElementExpression + + if ( + !bodyExpression.children.length || + bodyExpression.children[0].type !== "JSXExpressionContainer" + ) { + return + } + + const codeExpression = ( + bodyExpression.children[0] as JSXExpressionContainer + ).expression + + if (codeExpression.type !== "Literal") { + return + } + + const highlightsAttr = bodyExpression.openingElement?.attributes.find( + (attr) => attr.name.name === "highlights" + ) + + if (!highlightsAttr) { + return + } + + let highlights: string[][] | undefined + if ( + highlightsAttr.value.expression.type !== "Identifier" && + highlightsAttr.value.expression.type === "ArrayExpression" + ) { + const highlightsJs = getExpressionJsVarFromArrExpression( + highlightsAttr.value.expression as ArrayExpression + ) + if (!highlightsJs || !Array.isArray(highlightsJs)) { + return + } + highlights = getHighlightsFromExpressionJsVar(highlightsJs) + + if (!highlights) { + return + } + } else { + if (highlightsAttr.value.expression.type !== "Identifier") { + return + } + const name = (highlightsAttr.value.expression as Identifier).name + highlights = highlightConsts.get(name) + + if (!highlights) { + return + } + } + + const code = (codeExpression as LiteralExpression).value as string + + validateCodeHighlights({ + highlights, + code, + verbose, + }) + }) + } +} + +const getExpressionJsVarFromArrExpression = ( + expression: ArrayExpression +): ExpressionJsVar[][] => { + if (!Array.isArray(expression.elements)) { + return [] + } + return expression.elements.map((elm) => { + const elmJsVar = expressionToJs(elm) + if (!elmJsVar || !Array.isArray(elmJsVar)) { + return [] + } + return elmJsVar + }) +} + +const getHighlightsFromExpressionJsVar = ( + expression: ExpressionJsVar[] | ExpressionJsVar[][] +): string[][] | undefined => { + const highlights: string[][] = [] + const shouldExtractHighlights = !Array.isArray(expression[0]) + // the expression is an array where each three items are a highlight + // so we need to split the expression into groups of three items first + const highlightExpressions = shouldExtractHighlights + ? (expression as ExpressionJsVar[]).reduce((acc, item, index) => { + if (index % 3 === 0) { + acc.push([]) + } + acc[acc.length - 1].push(item) + return acc + }, [] as ExpressionJsVar[][]) + : (expression as ExpressionJsVar[][]) + + if (!highlightExpressions.length) { + return undefined + } + + for (const highlightExpression of highlightExpressions) { + if (highlightExpression.length !== 3) { + continue + } + + const highlight = [] + for (const item of highlightExpression) { + if (typeof item.data !== "string") { + continue + } + highlight.push(item.data) + } + highlights.push(highlight) + } + + return !highlights.length ? undefined : highlights +} + +/** + * Validates that the highlights of each code block are correct. It validates: + * + * 1. The highlight's first parameter is a string number of a valid line number in the code block. + * 2. The highlight's second parameter is a string that is a valid text in the line of the code block. + */ +const validateCodeHighlights = ({ + highlights, + code, + verbose, +}: { + highlights: string[][] + code: string + verbose?: boolean +}): void => { + try { + const lines = code.trim().split("\n") + for (const highlight of highlights) { + if (highlight.length < 2) { + throw new Error(`Highlight array must have at least 2 elements`) + } + + const lineNumber = highlight[0] + const text = highlight[1] + + if (typeof lineNumber !== "string" || typeof text !== "string") { + throw new Error(`Highlight array must have at least 2 elements`) + } + + if (isNaN(Number(lineNumber))) { + throw new Error(`Highlight line number must be a number`) + } + + const line = lines[Number(lineNumber) - 1]?.trim() + if (line === undefined) { + throw new Error(`Highlight line number ${lineNumber} not found in code`) + } + + if (text.length && !line.includes(text)) { + throw new Error( + `Highlight text ${text} not found in line ${lineNumber}` + ) + } + } + } catch (err) { + throw new Error( + formatError({ + message: (err as Error).message, + code, + verbose, + }) + ) + } +} + +const formatError = ({ + message, + code, + verbose, +}: { + message: string + code: string + verbose?: boolean +}): string => { + return `${message}${verbose ? `:\n${code}` : ""}` +} diff --git a/www/packages/types/src/remark-rehype.ts b/www/packages/types/src/remark-rehype.ts index c52de3a3bb..bfb10484b8 100644 --- a/www/packages/types/src/remark-rehype.ts +++ b/www/packages/types/src/remark-rehype.ts @@ -41,6 +41,10 @@ export type LiteralExpression = { export type JSXElementExpression = { type: "JSXElement" | "JSXFragment" children: Expression[] + openingElement: { + type: "JSXOpeningElement" + attributes: UnistJSXAttributeNode[] + } } export type JSXTextExpression = { @@ -49,6 +53,33 @@ export type JSXTextExpression = { raw: string } +export type VariableDeclaration = { + type: "VariableDeclaration" + declarations: VariableDeclarator[] +} +export type VariableDeclarator = { + type: "VariableDeclarator" + id: Identifier + init: Expression +} + +export type Identifier = { + type: "Identifier" + name: string +} + +export type TemplateLiteralExpression = { + type: "TemplateLiteral" + expressions: Expression[] + quasis: { + type: "TemplateElement" + value: { + raw: string + cooked: string + } + }[] +} + export type Expression = | { type: string @@ -60,10 +91,28 @@ export type Expression = | JSXTextExpression export interface Estree { - body?: { - type?: string - expression?: Expression - }[] + body?: ( + | { + type?: "ExpressionStatement" + expression?: Expression + } + | { + type?: "ExportNamedDeclaration" + declaration?: VariableDeclaration + } + )[] +} + +export interface UnistJSXAttributeNode { + type: "JSXAttribute" + name: { + type: "JSXIdentifier" + name: string + } + value: { + type: "JSXExpressionContainer" + expression: Identifier | Expression + } } export interface UnistNodeWithData extends UnistNode { @@ -244,3 +293,8 @@ export type ExpressionJsVarObj = { } export type ExpressionJsVar = ExpressionJsVarObj | ExpressionJsVarLiteral + +export type JSXExpressionContainer = { + type: "JSXExpressionContainer" + expression: Expression +}