From f4ed564dddd7bbd703a14ccec182140593f86a72 Mon Sep 17 00:00:00 2001 From: Kian Newman-Hazel Date: Tue, 4 Feb 2025 14:00:47 +0000 Subject: [PATCH 1/3] [Docs Site] Refactor partials property validation and docs --- astro.config.ts | 3 +- src/components/Render.astro | 42 +++-- src/content.config.ts | 9 +- .../identity/idp-integration/entra-id.mdx | 2 +- .../docs/style-guide/components/markdown.mdx | 6 + .../docs/style-guide/components/render.mdx | 178 +++++++++++++----- .../access/enable-scim-on-dashboard.mdx | 5 +- .../partials/style-guide/code-in-props.mdx | 38 ++++ src/content/partials/style-guide/hello.mdx | 14 -- .../partials/style-guide/image-in-props.mdx | 13 ++ .../partials/style-guide/link-in-props.mdx | 20 ++ .../partials/style-guide/optional-props.mdx | 23 +++ .../partials/style-guide/simple-props.mdx | 6 + .../partials/style-guide/strong-in-props.mdx | 15 ++ src/schemas/partials.ts | 27 ++- 15 files changed, 315 insertions(+), 86 deletions(-) create mode 100644 src/content/partials/style-guide/code-in-props.mdx delete mode 100644 src/content/partials/style-guide/hello.mdx create mode 100644 src/content/partials/style-guide/image-in-props.mdx create mode 100644 src/content/partials/style-guide/link-in-props.mdx create mode 100644 src/content/partials/style-guide/optional-props.mdx create mode 100644 src/content/partials/style-guide/simple-props.mdx create mode 100644 src/content/partials/style-guide/strong-in-props.mdx diff --git a/astro.config.ts b/astro.config.ts index d7099a81d7f5ff2..3e59ae1d5edd96a 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -8,14 +8,15 @@ import starlightLinksValidator from "starlight-links-validator"; import icon from "astro-icon"; import sitemap from "@astrojs/sitemap"; import react from "@astrojs/react"; + import { readdir } from "fs/promises"; +import { fileURLToPath } from "url"; import rehypeTitleFigure from "rehype-title-figure"; import rehypeMermaid from "./src/plugins/rehype/mermaid.ts"; import rehypeAutolinkHeadings from "./src/plugins/rehype/autolink-headings.ts"; import rehypeExternalLinks from "./src/plugins/rehype/external-links.ts"; import rehypeHeadingSlugs from "./src/plugins/rehype/heading-slugs.ts"; -import { fileURLToPath } from "url"; async function autogenSections() { const sections = ( diff --git a/src/components/Render.astro b/src/components/Render.astro index fd854e3aee7ab28..8583134d2de073b 100644 --- a/src/components/Render.astro +++ b/src/components/Render.astro @@ -13,29 +13,49 @@ const props = z.object({ let { file, product, params } = props.parse(Astro.props); if (!product) { - product = Astro.params.slug?.split("/")[0]; -} + const fromSlug = Astro.params.slug?.split("/")[0]; -if (!product) { - throw new Error( - `[Render] Unable to infer which folder ${file} is in, please provide a "product" input with your "file" input.`, - ); + if (!fromSlug) { + throw new Error( + `[Render] Unable to infer which folder ${file} is in, please provide a "product" input with your "file" input.`, + ); + } + + product = fromSlug; } -const partial = await getEntry("partials", `${product}/${file}`); +const id = `${product}/${file}`; +const partial = await getEntry("partials", id); if (!partial) { throw new Error( - `[Render] Couldn't find partial: ${file}. Included on ${Astro.params.slug}`, + `[Render] Couldn't find "${id}" included on "${Astro.url.pathname}"`, ); } +// We currently only enforce parameters if `params` is set in the frontmatter, +// until we can migrate existing `inputParameters` frontmatter to `params`. if (partial.data.params) { - const expected = partial.data.params; - if (!params) + const expected = partial.data.params.sort(); + const optional = expected.filter((p) => p.endsWith("?")); + const received = Object.keys(params ?? {}).sort(); + + const maximum = expected.length; + const minimum = maximum - optional.length; + + if ( + received.length < minimum || + received.length > maximum || + expected.some((p: string) => { + if (p.endsWith("?")) return false; + + return !received.includes(p); + }) + ) { throw new Error( - `${file} included on ${Astro.params.slug} expected parameters: ${expected}, got none`, + `[Render] Expected parameters ${JSON.stringify(expected)} but received parameters ${JSON.stringify(received)} for "${file}" included on "${Astro.url.pathname}"`, ); + } } const { Content } = await render(partial); diff --git a/src/content.config.ts b/src/content.config.ts index 5f8f1f01d0f4bb2..3a7e99ec2fcd66b 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -1,4 +1,4 @@ -import { z, defineCollection } from "astro:content"; +import { defineCollection } from "astro:content"; import { docsLoader, i18nLoader } from "@astrojs/starlight/loaders"; import { docsSchema, i18nSchema } from "@astrojs/starlight/schema"; @@ -20,6 +20,7 @@ import { warpReleasesSchema, changelogsNextSchema, fieldsSchema, + partialsSchema, } from "~/schemas"; function contentLoader(name: string) { @@ -36,10 +37,6 @@ function dataLoader(name: string) { }); } -const partialSchema = z.object({ - params: z.string().array().optional(), -}); - export const collections = { docs: defineCollection({ loader: docsLoader(), @@ -61,7 +58,7 @@ export const collections = { }), partials: defineCollection({ loader: contentLoader("partials"), - schema: partialSchema, + schema: partialsSchema, }), glossary: defineCollection({ loader: dataLoader("glossary"), diff --git a/src/content/docs/cloudflare-one/identity/idp-integration/entra-id.mdx b/src/content/docs/cloudflare-one/identity/idp-integration/entra-id.mdx index 51d66ac873662dd..e22cde97e6ad469 100644 --- a/src/content/docs/cloudflare-one/identity/idp-integration/entra-id.mdx +++ b/src/content/docs/cloudflare-one/identity/idp-integration/entra-id.mdx @@ -120,7 +120,7 @@ The Microsoft Entra ID integration allows you to synchronize IdP groups and auto ### 2. Configure SCIM in Entra ID diff --git a/src/content/docs/style-guide/components/markdown.mdx b/src/content/docs/style-guide/components/markdown.mdx index 38a51a2bfc435c4..22ef08a65198b32 100644 --- a/src/content/docs/style-guide/components/markdown.mdx +++ b/src/content/docs/style-guide/components/markdown.mdx @@ -2,6 +2,12 @@ title: Markdown --- +:::caution +This component does not use Astro to render the Markdown, as a result it cannot use components, `~/assets/` images or code blocks. + +Where feasible, use [JSX](/style-guide/components/render/#properties-as-markdown-syntax) instead +::: + This component uses `marked` to turn the `text` prop into HTML. This is useful with, for example partial files that have variables you need to format. ```mdx live diff --git a/src/content/docs/style-guide/components/render.mdx b/src/content/docs/style-guide/components/render.mdx index 23069da3b383d66..57060bbe4d84a54 100644 --- a/src/content/docs/style-guide/components/render.mdx +++ b/src/content/docs/style-guide/components/render.mdx @@ -2,90 +2,174 @@ title: Render --- -import { Steps } from "~/components"; +import { Code, Details, Type, MetaInfo } from "~/components"; The `Render` component allows us to include a "partial", a reusable Markdown snippet, onto a page. -It also accepts parameters that can be used as variables within the partial, so that even content -which needs slight differences between usages can be turned into a partial. +It also accepts parameters that can be used as variables within the partial, so that even content which needs slight differences between usages can be turned into a partial. ## Component ```mdx live import { Render } from "~/components"; - -{/* -Hello, {props.name}! +``` -Hello `{props.name}` +### Inputs -Hello {props.name} +- `file` -[link]({props.link}) + This should be the name of the partial, without the containing directory or file extension. For example, `/partials/style-guide/hello.mdx` would be `file="hello"`. -link -*/} -``` +- `product` -### Inputs + By default, it will look for partials in the same product folder as the current page. You can use this to specify a different product. + + :::caution + + When using the `Render` component inside partials, the original `product` is lost. + + For example, if there are three files: + + 1. `docs/fundamentals/index.mdx` + 2. `partials/dns/thing.mdx` + 3. `partials/dns/thing2.mdx` -**file** `string`: This should be the name of the partial, without the containing directory or file extension. -For example, `/partials/style-guide/hello.mdx` would be `file="hello"`. + `docs/fundamentals/index.mdx` uses `` -**product** `string` (optional): By default, it will look for partials in the same product folder as the current page. -You can use this to specify a different product. + `partials/dns/thing.mdx` must use `` as `product` cannot be inferred. -**params** `object` (optional): If you wish to substitute values inside your partial, you can use pass params which can be -referenced in your partial. Refer to [params](#params). + ::: -## Partials +- `params` -Partials only have one optional frontmatter property, which is `params`. This takes an array of strings, -which should be the expected parameters. When this is defined, but those parameters are not passed, an error -will be thrown. + If you wish to substitute values inside your partial, you can use pass params which can be referenced in your partial. Refer to [properties](#properties). -```mdx title="/src/content/partials/style-guide/hello.mdx" +## Properties + +### Defining expected properties in frontmatter + +Anything defined in the `params` property of the `Render` component is available inside the partial, using [JavaScript expressions](https://mdxjs.com/docs/using-mdx/). + +To protect against required properties being missed, any partial that relies on `params` should also define `params` in the partial's frontmatter. This should be an array of strings, matching the property names you expect. If a property is optional, such as for [conditional content](#properties-to-render-content-conditionally), add a `?` to the end of the name. + +```mdx --- params: - - name - - foo - - bar + - product + - deprecated? --- +``` + +For each of the below examples, you can open the dropdown to view the partial's content. + +### Properties as a plain string + +The below example would render `Hello, world!`. + +import simpleRaw from "~/content/partials/style-guide/simple-props.mdx?raw"; + +
+ +
+ +```mdx live +import { Render } from "~/components"; + + +``` + +### Properties in Markdown syntax + +When using JavaScript expressions, you are now "inside JSX" and cannot use traditional Markdown syntax. Similarly, you cannot use a JavaScript expression inside Markdown syntax. + +Ideally, you should not use Markdown syntax, such as `**strong**` or `[text](link)`, with properties. If using JSX is not feasible, there is a [`Markdown`](/style-guide/components/markdown/) component that will take a `text` property. + +The [MDX documentation](https://mdxjs.com/table-of-components/#components) includes a mapping of common Markdown syntax to their equivalent JSX elements. + +#### Strong + +import strongRaw from "~/content/partials/style-guide/strong-in-props.mdx?raw"; -Hello, {props.name}! +
+ +
-Hello, {props.foo}! +```mdx live +import { Render } from "~/components"; -Hello, {props.bar}! + ``` -### Params +#### Links + +import linkRaw from "~/content/partials/style-guide/link-in-props.mdx?raw"; + +
+ +
-In the above example, you will notice there is: +```mdx live +import { Render } from "~/components"; - + +``` -1. A `params` input on the `Render` component. -2. A `params` property in the frontmatter. -3. A reference to `props.name`. +#### Images + +import imageRaw from "~/content/partials/style-guide/image-in-props.mdx?raw"; + +
+ +
+ +```mdx live +import { Render } from "~/components"; + + +``` -
+#### Code blocks -#### Input +import codeRaw from "~/content/partials/style-guide/code-in-props.mdx?raw"; + +
+ +
+ +```mdx live +import { Render } from "~/components"; + + +``` + +### Properties to render content conditionally + +Anything that you can represent in a JavaScript expression can be used in your conditional logic. + +This may be the [and (`&&`) operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND) or [ternary (`? ... : ... `) operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator), the below example uses both. + +import optionalRaw from "~/content/partials/style-guide/optional-props.mdx?raw"; + +
+ +
+ +```mdx live +import { Render } from "~/components"; -When using the `params` input on the `Render` component, you can write a [JavaScript object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_objects) -which is later available inside the partial. + -#### Frontmatter +
-The `params` frontmatter property on a partial expects an array of strings, containing the "expected parameters". This is so that if -your partial requires parameters to be passed, and none are passed, we can warn the user. + -#### Props +
-The way that you can access these parameters is with the `props` object, surrounded in curly braces `{}`. -This is a [JavaScript expression within MDX](https://mdxjs.com/docs/using-mdx/#props). + +``` \ No newline at end of file diff --git a/src/content/partials/cloudflare-one/access/enable-scim-on-dashboard.mdx b/src/content/partials/cloudflare-one/access/enable-scim-on-dashboard.mdx index 3878ec8c43e369a..ccd70df213801fe 100644 --- a/src/content/partials/cloudflare-one/access/enable-scim-on-dashboard.mdx +++ b/src/content/partials/cloudflare-one/access/enable-scim-on-dashboard.mdx @@ -1,8 +1,7 @@ --- params: - idp - - and - - supportgroups + - supportgroups? --- import { Markdown } from "~/components" @@ -11,7 +10,7 @@ import { Markdown } from "~/components" 2. Find the {props.idp} integration and select **Edit**. -3. Turn on **Enable SCIM**{props.and}**{props.supportgroups}**. +3. Turn on **Enable SCIM** {props.supportgroups && and props.supportgroups.} 4. (Optional) Configure the following settings: diff --git a/src/content/partials/style-guide/code-in-props.mdx b/src/content/partials/style-guide/code-in-props.mdx new file mode 100644 index 000000000000000..2ab5ae3c688bbc5 --- /dev/null +++ b/src/content/partials/style-guide/code-in-props.mdx @@ -0,0 +1,38 @@ +--- +params: + - code +--- + +import { Code } from "~/components"; + +#### Inline + +**Don't do this!** + +`` `{props.code}` `` + +**Do this!** + +`{props.code}` +{props.code} + +
+ +#### Codeblocks + +**Don't do this!** + +```` +```js +{props.code} +``` +```` + +```js +{props.code} +``` + +**Do this!** + +`` + \ No newline at end of file diff --git a/src/content/partials/style-guide/hello.mdx b/src/content/partials/style-guide/hello.mdx deleted file mode 100644 index 2fefdcfb8641b71..000000000000000 --- a/src/content/partials/style-guide/hello.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -params: - - name ---- - -Hello, {props.name}! - -Hello `{props.name}` - -Hello {props.name} - -[link]({props.link}) (href="%7Bprops.link%7D") - -link (href="/style-guide/components/render/") \ No newline at end of file diff --git a/src/content/partials/style-guide/image-in-props.mdx b/src/content/partials/style-guide/image-in-props.mdx new file mode 100644 index 000000000000000..a78a4a47710d51e --- /dev/null +++ b/src/content/partials/style-guide/image-in-props.mdx @@ -0,0 +1,13 @@ +--- +params: + - image +--- + +**Don't do this!** + +`![Alt text]({props.image})` + +**Do this!** + +`Alt text` +Alt text \ No newline at end of file diff --git a/src/content/partials/style-guide/link-in-props.mdx b/src/content/partials/style-guide/link-in-props.mdx new file mode 100644 index 000000000000000..b00f83be5c25ed9 --- /dev/null +++ b/src/content/partials/style-guide/link-in-props.mdx @@ -0,0 +1,20 @@ +--- +params: + - link +--- + +**Don't do this!** + +This will link to `/style-guide/components/%7Bprops.link%7D`. + +`[Markdown link]({props.link})` + +[Markdown link]({props.link}) + +**Do this!** + +This will link to `style-guide/components/render/#links`. + +`JSX link` + +JSX link \ No newline at end of file diff --git a/src/content/partials/style-guide/optional-props.mdx b/src/content/partials/style-guide/optional-props.mdx new file mode 100644 index 000000000000000..6c6256808676eab --- /dev/null +++ b/src/content/partials/style-guide/optional-props.mdx @@ -0,0 +1,23 @@ +--- +params: + - product + - deprecated? +--- + +{ + props.deprecated && ( +

+ + {props.product} is deprecated, please use alternative products. + +

+ ) +} + +{ + props.product === "Thing Three" ? ( +

Welcome to our Thing Three launch countdown!

+ ) : ( +

Welcome to the {props.product} landing page.

+ ) +} diff --git a/src/content/partials/style-guide/simple-props.mdx b/src/content/partials/style-guide/simple-props.mdx new file mode 100644 index 000000000000000..89a65604442455c --- /dev/null +++ b/src/content/partials/style-guide/simple-props.mdx @@ -0,0 +1,6 @@ +--- +params: + - name +--- + +Hello, {props.name}! \ No newline at end of file diff --git a/src/content/partials/style-guide/strong-in-props.mdx b/src/content/partials/style-guide/strong-in-props.mdx new file mode 100644 index 000000000000000..6606b8d832851e9 --- /dev/null +++ b/src/content/partials/style-guide/strong-in-props.mdx @@ -0,0 +1,15 @@ +--- +params: + - dont + - do +--- + +**Don't do this!** + +`{props.dont}` +{props.dont} + +**Do this!** + +`{props.do}` +{props.do} \ No newline at end of file diff --git a/src/schemas/partials.ts b/src/schemas/partials.ts index 0acc176a4fb0684..58e1c6075535219 100644 --- a/src/schemas/partials.ts +++ b/src/schemas/partials.ts @@ -1,5 +1,26 @@ import { z } from "astro:schema"; -export const partialSchema = z.object({ - params: z.string().array().optional(), -}); +const paramsDocs = + "https://developers.cloudflare.com/style-guide/components/render/#defining-expected-properties-in-frontmatter"; + +export const partialsSchema = z + .object({ + slug: z + .string() + .optional() + .describe( + "Used to define custom IDs: https://docs.astro.build/en/guides/content-collections/#defining-custom-ids", + ), + params: z + .string() + .array() + .optional() + .describe(`Used to define expected properties: ${paramsDocs}`), + inputParameters: z + .string() + .optional() + .describe( + `Deprecated - this field has no functionality, please migrate to ${paramsDocs}`, + ), + }) + .strict(); From 7f8eada877d29e698f71971e541bffb225d2be1a Mon Sep 17 00:00:00 2001 From: Kian Newman-Hazel Date: Tue, 4 Feb 2025 14:17:48 +0000 Subject: [PATCH 2/3] update partial examples --- src/content/partials/style-guide/code-in-props.mdx | 12 ++---------- src/content/partials/style-guide/image-in-props.mdx | 1 - src/content/partials/style-guide/link-in-props.mdx | 6 +----- src/content/partials/style-guide/strong-in-props.mdx | 2 -- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/content/partials/style-guide/code-in-props.mdx b/src/content/partials/style-guide/code-in-props.mdx index 2ab5ae3c688bbc5..12bd2c918db1357 100644 --- a/src/content/partials/style-guide/code-in-props.mdx +++ b/src/content/partials/style-guide/code-in-props.mdx @@ -9,12 +9,11 @@ import { Code } from "~/components"; **Don't do this!** -`` `{props.code}` `` +`{props.code}` **Do this!** -`{props.code}` -{props.code} +

{props.code}


@@ -22,17 +21,10 @@ import { Code } from "~/components"; **Don't do this!** -```` -```js -{props.code} -``` -```` - ```js {props.code} ``` **Do this!** -`` \ No newline at end of file diff --git a/src/content/partials/style-guide/image-in-props.mdx b/src/content/partials/style-guide/image-in-props.mdx index a78a4a47710d51e..cca4506f76e98c6 100644 --- a/src/content/partials/style-guide/image-in-props.mdx +++ b/src/content/partials/style-guide/image-in-props.mdx @@ -9,5 +9,4 @@ params: **Do this!** -`Alt text` Alt text \ No newline at end of file diff --git a/src/content/partials/style-guide/link-in-props.mdx b/src/content/partials/style-guide/link-in-props.mdx index b00f83be5c25ed9..75e80a9ba4bab7a 100644 --- a/src/content/partials/style-guide/link-in-props.mdx +++ b/src/content/partials/style-guide/link-in-props.mdx @@ -7,14 +7,10 @@ params: This will link to `/style-guide/components/%7Bprops.link%7D`. -`[Markdown link]({props.link})` - [Markdown link]({props.link}) **Do this!** This will link to `style-guide/components/render/#links`. -`JSX link` - -JSX link \ No newline at end of file +

JSX link

\ No newline at end of file diff --git a/src/content/partials/style-guide/strong-in-props.mdx b/src/content/partials/style-guide/strong-in-props.mdx index 6606b8d832851e9..70fdd5cc28422c0 100644 --- a/src/content/partials/style-guide/strong-in-props.mdx +++ b/src/content/partials/style-guide/strong-in-props.mdx @@ -6,10 +6,8 @@ params: **Don't do this!** -`{props.dont}` {props.dont} **Do this!** -`{props.do}` {props.do} \ No newline at end of file From 96dc6131f3e44b79ef3f7885723bc3623950b812 Mon Sep 17 00:00:00 2001 From: Kian Newman-Hazel Date: Tue, 4 Feb 2025 14:28:32 +0000 Subject: [PATCH 3/3] update anchor in markdown component aside --- src/content/docs/style-guide/components/markdown.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/style-guide/components/markdown.mdx b/src/content/docs/style-guide/components/markdown.mdx index 22ef08a65198b32..a40df4d0024c33c 100644 --- a/src/content/docs/style-guide/components/markdown.mdx +++ b/src/content/docs/style-guide/components/markdown.mdx @@ -5,7 +5,7 @@ title: Markdown :::caution This component does not use Astro to render the Markdown, as a result it cannot use components, `~/assets/` images or code blocks. -Where feasible, use [JSX](/style-guide/components/render/#properties-as-markdown-syntax) instead +Where feasible, use [JSX](/style-guide/components/render/#properties-in-markdown-syntax) instead ::: This component uses `marked` to turn the `text` prop into HTML. This is useful with, for example partial files that have variables you need to format.