Skip to content

Commit c97f268

Browse files
Allow adding a default ist of platforms URLs for social links
1 parent 517ac5c commit c97f268

5 files changed

Lines changed: 291 additions & 172 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fujocoded/zod-transform-socials": patch
3+
---
4+
5+
Add `createSocialsTransformer` for registering custom domains for platforms without known URL shapes (currently `mastodon`), so self-hosted instances can be matched without needing to spell out `platform` every time.

zod-transform-socials/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,39 @@ interface Props {
5454
contacts: SocialLinksData;
5555
}
5656
```
57+
58+
## Adding custom domains
59+
60+
For platforms without a fixed domain, like `mastodon`, the built-in matchers
61+
can only know a fixed set of domains (e.g. `mastodon.social`,
62+
`mastodon.world`). If you use a different instance and you're tired of
63+
spelling out `platform: mastodon` every time, you can use `createSocialsTransformer`
64+
and pass platform domains via `domains`:
65+
66+
```ts
67+
import { createSocialsTransformer } from "@fujocoded/zod-transform-socials";
68+
69+
const { SocialLinks, transformSocial } = createSocialsTransformer({
70+
domains: {
71+
mastodon: ["blorbo.social", "tech.lgbt", "indiepocalypse.social"],
72+
},
73+
});
74+
75+
export const teamCollection = defineCollection({
76+
type: "data",
77+
schema: (tools) =>
78+
z.object({
79+
// ...
80+
contacts: SocialLinks,
81+
}),
82+
});
83+
```
84+
85+
Only platforms with a registered URL shape can be configured this way
86+
(currently: `mastodon`). If you need a platform that isn't covered, please
87+
open a PR to add its URL-shape builder to `DOMAIN_PATTERNS` in the library —
88+
that way every consumer benefits and patterns stay correct.
89+
90+
The bare `SocialLinks` / `transformSocial` exports still work and use the
91+
default configuration — only switch to `createSocialsTransformer` when you
92+
need to add domains.

zod-transform-socials/index.ts

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import z from "zod";
2-
import { extractSocialData, getSocialIcon } from "./socials.ts";
3-
import type { SOCIAL_TYPES as INNER_SOCIAL_TYPES } from "./social-links.ts";
2+
import {
3+
createExtractSocialData,
4+
extractSocialData,
5+
getSocialIcon,
6+
} from "./socials.ts";
7+
import {
8+
createSocialLinks,
9+
type CreateSocialLinksConfig,
10+
type DomainShortcuts,
11+
type SOCIAL_TYPES as INNER_SOCIAL_TYPES,
12+
} from "./social-links.ts";
413

514
export const SocialsSchema = z.union([
615
z.string().url(),
@@ -14,26 +23,47 @@ export const SocialsSchema = z.union([
1423

1524
export type SocialsSchema = z.infer<typeof SocialsSchema>;
1625

17-
export const transformSocial = (social: SocialsSchema) => {
18-
if (typeof social == "string") {
19-
return extractSocialData({ url: social });
20-
}
21-
const { icon, url, platform, username } = social;
22-
const data = extractSocialData({ url });
23-
24-
return {
25-
icon:
26-
icon ??
27-
(platform === undefined
28-
? data.icon
29-
: getSocialIcon(platform as INNER_SOCIAL_TYPES)),
30-
url: url ?? data.url,
31-
platform: platform ?? data.platform,
32-
username: username ?? data.username,
26+
export type SOCIAL_TYPES = INNER_SOCIAL_TYPES;
27+
export type { DomainShortcuts };
28+
29+
export type CreateSocialsConfig = CreateSocialLinksConfig;
30+
31+
const buildTransformSocial =
32+
(extractor: ReturnType<typeof createExtractSocialData>) =>
33+
(social: SocialsSchema) => {
34+
if (typeof social == "string") {
35+
return extractor({ url: social });
36+
}
37+
const { icon, url, platform, username } = social;
38+
const data = extractor({ url });
39+
40+
return {
41+
icon:
42+
icon ??
43+
(platform === undefined
44+
? data.icon
45+
: getSocialIcon(platform as INNER_SOCIAL_TYPES)),
46+
url: url ?? data.url,
47+
platform: platform ?? data.platform,
48+
username: username ?? data.username,
49+
};
3350
};
51+
52+
export const createSocialsTransformer = (config: CreateSocialsConfig = {}) => {
53+
const socialLinks = createSocialLinks(config);
54+
const extractor = createExtractSocialData(socialLinks);
55+
const transformSocial = buildTransformSocial(extractor);
56+
57+
const SocialLinks = z
58+
.array(SocialsSchema)
59+
.default([])
60+
.transform((socialUrls) => socialUrls.map(transformSocial));
61+
62+
return { SocialsSchema, transformSocial, SocialLinks, socialLinks };
3463
};
3564

36-
export type SOCIAL_TYPES = INNER_SOCIAL_TYPES;
65+
// Export a default transformer
66+
export const transformSocial = buildTransformSocial(extractSocialData);
3767

3868
export const SocialLinks = z
3969
.array(SocialsSchema)

0 commit comments

Comments
 (0)