Skip to content

Commit aaacc3c

Browse files
KianNHkodster28
andauthored
[Docs Site] Enforce and transform frontmatter tags (#22836)
* [Docs Site] Enforce and transform frontmatter tags * remove KV tags * other content updates * update tags docs and error --------- Co-authored-by: kodster28 <[email protected]>
1 parent 13eb0c5 commit aaacc3c

File tree

10 files changed

+151
-85
lines changed

10 files changed

+151
-85
lines changed

astro.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export default defineConfig({
160160
markdown: {
161161
headingLinks: false,
162162
},
163+
routeMiddleware: "./src/plugins/starlight/route-data.ts",
163164
}),
164165
liveCode({}),
165166
icon(),

src/components/TagsUsage.astro

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
---
22
import { getCollection } from "astro:content";
3+
import { tags as allowedTags } from "~/schemas/tags";
4+
35
import AnchorHeading from "./AnchorHeading.astro";
46
import Details from "./Details.astro";
57
@@ -13,28 +15,57 @@ for (const entry of entries) {
1315
byTag[tag].push(entry.id);
1416
}
1517
}
18+
19+
const flattened = Object.values(allowedTags).flat();
1620
---
1721

1822
{
1923
Object.entries(byTag)
2024
.sort()
21-
.map(([tag, pages]) => (
22-
<>
23-
<AnchorHeading depth={3} title={tag} />
24-
<p>
25-
<code>{tag}</code> is used on <code>{pages.length}</code> pages.
26-
</p>
27-
<Details header={`Pages tagged with ${tag}`}>
28-
<ul>
29-
{pages.map((path) => (
25+
.map(([tag, pages]) => {
26+
const pretty = flattened.find(
27+
(x) =>
28+
x.label.toLowerCase() === tag.toLowerCase() ||
29+
x.variants?.find((v) => v.toLowerCase() === tag.toLowerCase()),
30+
);
31+
32+
if (!pretty) {
33+
throw new Error(
34+
`[TagsUsage] Tag ${tag} not found in /src/schemas/tags.ts`,
35+
);
36+
}
37+
38+
return (
39+
<>
40+
<AnchorHeading depth={3} title={pretty.label} />
41+
{pretty.variants && pretty.variants.length > 0 && (
42+
<p>
43+
Variants:
44+
</p>
45+
<ul>
46+
{pretty.variants?.map((variant) => (
3047
<li>
31-
<a href={`/${path}/`} target="_blank">
32-
{path}
33-
</a>
48+
<code>{variant}</code>
3449
</li>
3550
))}
3651
</ul>
37-
</Details>
38-
</>
39-
))
52+
)}
53+
<p>
54+
Used on <code>{pages.length}</code>{" "}
55+
pages.
56+
</p>
57+
<Details header={`Pages tagged with ${pretty.label}`}>
58+
<ul>
59+
{pages.map((path) => (
60+
<li>
61+
<a href={`/${path}/`} target="_blank">
62+
{path}
63+
</a>
64+
</li>
65+
))}
66+
</ul>
67+
</Details>
68+
</>
69+
);
70+
})
4071
}

src/content/docs/kv/examples/cache-data-with-workers-kv.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
---
22
type: example
33
summary: Cache data or API responses in Workers KV to improve application performance
4-
tags:
5-
- KV
64
pcx_content_type: configuration
75
title: Cache data with Workers KV
86
sidebar:

src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
---
22
type: example
33
summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
4-
tags:
5-
- KV
64
pcx_content_type: configuration
75
title: Build a distributed configuration store
86
sidebar:
@@ -19,7 +17,7 @@ In this example, application configuration data is used to personalize the Worke
1917
## Write your configuration from your external application to Workers KV
2018

2119
In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
22-
If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace.
20+
If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace.
2321

2422
The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
2523

@@ -31,63 +29,65 @@ const { Cloudflare } = require('cloudflare');
3129
const { backOff } = require('exponential-backoff');
3230

3331
if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
34-
console.error('Missing required environment variables.');
35-
process.exit(1);
32+
console.error('Missing required environment variables.');
33+
process.exit(1);
3634
}
3735

3836
// Setup Postgres connection
3937
const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
4038

4139
// Setup Cloudflare REST API client
4240
const client = new Cloudflare({
43-
apiEmail: process.env.CLOUDFLARE_EMAIL,
44-
apiKey: process.env.CLOUDFLARE_API_KEY,
41+
apiEmail: process.env.CLOUDFLARE_EMAIL,
42+
apiKey: process.env.CLOUDFLARE_API_KEY,
4543
});
4644

4745
// Function to sync Postgres data to Workers KV
4846
async function syncPreviewStatus() {
49-
console.log('Starting sync of user preview status...');
50-
51-
try {
52-
// Get all users and their preview status
53-
const users = await sql`SELECT id, preview_features_enabled FROM users`;
54-
55-
console.log(users);
56-
57-
// Create the bulk update body
58-
const bulkUpdateBody = users.map(user => ({
59-
key: user.id,
60-
value: JSON.stringify({
61-
preview_features_enabled: user.preview_features_enabled
62-
})
63-
}));
64-
65-
const response = await backOff(async () => {
66-
console.log("trying to update")
67-
try{
68-
const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
69-
account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
70-
body: bulkUpdateBody
71-
});
72-
}
73-
catch(e){
74-
// Implement your error handling and logging here
75-
console.log(e);
76-
throw e; // Rethrow the error to retry
77-
}
78-
});
79-
80-
console.log(`Sync complete. Updated ${users.length} users.`);
81-
} catch (error) {
82-
console.error('Error syncing preview status:', error);
83-
}
47+
console.log('Starting sync of user preview status...');
48+
49+
try {
50+
// Get all users and their preview status
51+
const users = await sql`SELECT id, preview_features_enabled FROM users`;
52+
53+
console.log(users);
54+
55+
// Create the bulk update body
56+
const bulkUpdateBody = users.map(user => ({
57+
key: user.id,
58+
value: JSON.stringify({
59+
preview_features_enabled: user.preview_features_enabled
60+
})
61+
}));
62+
63+
const response = await backOff(async () => {
64+
console.log("trying to update")
65+
try{
66+
const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
67+
account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
68+
body: bulkUpdateBody
69+
});
70+
}
71+
catch(e){
72+
// Implement your error handling and logging here
73+
console.log(e);
74+
throw e; // Rethrow the error to retry
75+
}
76+
});
77+
78+
console.log(`Sync complete. Updated ${users.length} users.`);
79+
} catch (error) {
80+
console.error('Error syncing preview status:', error);
81+
}
82+
8483
}
8584

8685
// Run the sync function
8786
syncPreviewStatus()
88-
.catch(console.error)
89-
.finally(() => process.exit(0));
90-
```
87+
.catch(console.error)
88+
.finally(() => process.exit(0));
89+
90+
````
9191
</TabItem>
9292
<TabItem label=".env">
9393
```md title=".env"
@@ -225,7 +225,7 @@ This code will use the path within the URL and find the file associated to the p
225225
226226
## Optimize performance for configuration
227227
228-
To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may benefit from higher caching efficiency and lower latency.
228+
To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may benefit from higher caching efficiency and lower latency.
229229
230230
For example, instead of storing each user's configuration in a separate key-value pair, you may store all users' configurations in a single key-value pair. This approach may be suitable for use-cases where the configuration data is small and can be easily managed in a single key-value pair (the [size limit for a Workers KV value is 25 MiB](/kv/platform/limits/)).
231231
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
---
22
type: example
33
summary: Use Workers KV to store A/B testing configuration data and analyze the performance of different versions of your website
4-
tags:
5-
- KV
64
pcx_content_type: configuration
75
title: A/B testing with Workers KV
86
external_link: /reference-architecture/diagrams/serverless/a-b-testing-using-workers/
97
sidebar:
108
order: 6
11-
---
9+
---

src/content/docs/kv/examples/routing-with-workers-kv.mdx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
---
22
type: example
33
summary: Store routing data in Workers KV to route requests across various web servers with Workers
4-
tags:
5-
- KV
64
pcx_content_type: configuration
75
title: Route requests across various web servers
86
sidebar:
@@ -16,7 +14,6 @@ Using Workers KV to store routing data to route requests across various web serv
1614

1715
Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.
1816

19-
2017
In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (for example, requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server).
2118

2219
In multi-tenant applications, requests can be routed to the tenant's respective origin resources (for example, requests to `tenantA.your-worker-hostname.com` routed to server for Tenant A, `tenantB.your-worker-hostname.com` routed to server for Tenant B).
@@ -142,7 +139,6 @@ In this example, the Cloudflare Worker receives a request and extracts the store
142139
The storefront ID is used to look up the origin server URL from Workers KV using the `get()` method.
143140
The request is then forwarded to the origin server, and the response is modified to include custom headers before being returned to the client.
144141
145-
146142
## Related resources
147143
148144
- [Rust support in Workers](/workers/languages/rust/).

src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
---
22
type: example
33
summary: Store static assets in Workers KV and serve them from a Worker application with low-latency and high-throughput
4-
tags:
5-
- KV
64
pcx_content_type: configuration
75
title: Store and retrieve static assets
86
sidebar:

src/content/docs/style-guide/frontmatter/tags.mdx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TagsUsage } from "~/components";
66

77
Tags are currently used to filter content in the [`ExternalResources`](/style-guide/components/external-resources/), [`ProductsByTag`](/style-guide/components/products-by-tag/) and the [`ResourcesBySelector`](/style-guide/components/resources-by-selector/) components.
88

9-
## Examples
9+
## Example
1010

1111
```mdx
1212
---
@@ -17,6 +17,15 @@ tags:
1717
---
1818
```
1919

20-
## Tags
20+
## Allowed tags and where they are being used
2121

22-
<TagsUsage />
22+
Tags are validated against an allowlist in [`/src/schemas/tags.ts`](https://github.com/cloudflare/cloudflare-docs/blob/production/src/schemas/tags.ts) which defines the user-facing representation (`label`) and any associated variants.
23+
24+
The matching is case-insensitive. For example, all of the following values are accepted in the `tags` frontmatter array and will be transformed into `Node.js`:
25+
26+
- `node.js`
27+
- `NoDe.JS`
28+
- `node`
29+
- `nodejs`
30+
31+
<TagsUsage />
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { defineRouteMiddleware } from "@astrojs/starlight/route-data";
2+
import { tags as allowedTags } from "~/schemas/tags";
3+
4+
export const onRequest = defineRouteMiddleware(({ locals }) => {
5+
const { entry } = locals.starlightRoute;
6+
const { tags } = entry.data;
7+
8+
if (tags) {
9+
const transformed = tags.map((tag) => {
10+
const values = Object.values(allowedTags).flat();
11+
12+
const match = values.find(
13+
(val) =>
14+
val.label.toLowerCase() === tag.toLowerCase() ||
15+
val.variants?.find((v) => v.toLowerCase() === tag.toLowerCase()),
16+
);
17+
18+
if (!match) {
19+
throw new Error(
20+
`Invalid tag on ${entry.id}: ${tag}, please refer to the style guide: https://developers.cloudflare.com/style-guide/frontmatter/tags/`,
21+
);
22+
}
23+
24+
return match.label;
25+
});
26+
27+
entry.data.tags = transformed;
28+
}
29+
});

0 commit comments

Comments
 (0)