@docusaurus/plugin-content-blog 0.0.0-5994 → 0.0.0-5995

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/authors.js CHANGED
@@ -9,8 +9,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.validateAuthorsMap = validateAuthorsMap;
10
10
  exports.getAuthorsMap = getAuthorsMap;
11
11
  exports.getBlogPostAuthors = getBlogPostAuthors;
12
+ const tslib_1 = require("tslib");
13
+ const _ = tslib_1.__importStar(require("lodash"));
12
14
  const utils_1 = require("@docusaurus/utils");
13
15
  const utils_validation_1 = require("@docusaurus/utils-validation");
16
+ const authorsSocials_1 = require("./authorsSocials");
14
17
  const AuthorsMapSchema = utils_validation_1.Joi.object()
15
18
  .pattern(utils_validation_1.Joi.string(), utils_validation_1.Joi.object({
16
19
  name: utils_validation_1.Joi.string(),
@@ -18,6 +21,7 @@ const AuthorsMapSchema = utils_validation_1.Joi.object()
18
21
  imageURL: utils_validation_1.URISchema,
19
22
  title: utils_validation_1.Joi.string(),
20
23
  email: utils_validation_1.Joi.string(),
24
+ socials: authorsSocials_1.AuthorSocialsSchema,
21
25
  })
22
26
  .rename('image_url', 'imageURL')
23
27
  .or('name', 'imageURL')
@@ -37,12 +41,24 @@ function validateAuthorsMap(content) {
37
41
  }
38
42
  return value;
39
43
  }
44
+ function normalizeAuthor(author) {
45
+ return {
46
+ ...author,
47
+ socials: author.socials ? (0, authorsSocials_1.normalizeSocials)(author.socials) : undefined,
48
+ };
49
+ }
50
+ function normalizeAuthorsMap(authorsMap) {
51
+ return _.mapValues(authorsMap, normalizeAuthor);
52
+ }
40
53
  async function getAuthorsMap(params) {
41
- return (0, utils_1.getDataFileData)({
54
+ const authorsMap = await (0, utils_1.getDataFileData)({
42
55
  filePath: params.authorsMapPath,
43
56
  contentPaths: params.contentPaths,
44
57
  fileType: 'authors map',
45
- }, validateAuthorsMap);
58
+ },
59
+ // TODO annoying to test: tightly coupled FS reads + validation...
60
+ validateAuthorsMap);
61
+ return authorsMap ? normalizeAuthorsMap(authorsMap) : undefined;
46
62
  }
47
63
  function normalizeImageUrl({ imageURL, baseUrl, }) {
48
64
  return imageURL?.startsWith('/')
@@ -70,7 +86,7 @@ function getFrontMatterAuthorLegacy({ baseUrl, frontMatter, }) {
70
86
  return undefined;
71
87
  }
72
88
  function normalizeFrontMatterAuthors(frontMatterAuthors = []) {
73
- function normalizeAuthor(authorInput) {
89
+ function normalizeFrontMatterAuthor(authorInput) {
74
90
  if (typeof authorInput === 'string') {
75
91
  // Technically, we could allow users to provide an author's name here, but
76
92
  // we only support keys, otherwise, a typo in a key would fallback to
@@ -80,8 +96,8 @@ function normalizeFrontMatterAuthors(frontMatterAuthors = []) {
80
96
  return authorInput;
81
97
  }
82
98
  return Array.isArray(frontMatterAuthors)
83
- ? frontMatterAuthors.map(normalizeAuthor)
84
- : [normalizeAuthor(frontMatterAuthors)];
99
+ ? frontMatterAuthors.map(normalizeFrontMatterAuthor)
100
+ : [normalizeFrontMatterAuthor(frontMatterAuthors)];
85
101
  }
86
102
  function getFrontMatterAuthors(params) {
87
103
  const { authorsMap } = params;
@@ -105,11 +121,11 @@ ${Object.keys(authorsMap)
105
121
  return undefined;
106
122
  }
107
123
  function toAuthor(frontMatterAuthor) {
108
- return {
124
+ return normalizeAuthor({
109
125
  // Author def from authorsMap can be locally overridden by front matter
110
126
  ...getAuthorsMapAuthor(frontMatterAuthor.key),
111
127
  ...frontMatterAuthor,
112
- };
128
+ });
113
129
  }
114
130
  return frontMatterAuthors.map(toAuthor);
115
131
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { Joi } from '@docusaurus/utils-validation';
8
+ import type { AuthorSocials } from '@docusaurus/plugin-content-blog';
9
+ export declare const AuthorSocialsSchema: Joi.ObjectSchema<AuthorSocials>;
10
+ export declare const normalizeSocials: (socials: AuthorSocials) => AuthorSocials;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.normalizeSocials = exports.AuthorSocialsSchema = void 0;
10
+ const utils_validation_1 = require("@docusaurus/utils-validation");
11
+ exports.AuthorSocialsSchema = utils_validation_1.Joi.object({
12
+ twitter: utils_validation_1.Joi.string(),
13
+ github: utils_validation_1.Joi.string(),
14
+ linkedin: utils_validation_1.Joi.string(),
15
+ // StackOverflow userIds like '82609' are parsed as numbers by Yaml
16
+ stackoverflow: utils_validation_1.Joi.alternatives()
17
+ .try(utils_validation_1.Joi.number(), utils_validation_1.Joi.string())
18
+ .custom((val) => String(val)),
19
+ x: utils_validation_1.Joi.string(),
20
+ }).unknown();
21
+ const PredefinedPlatformNormalizers = {
22
+ x: (handle) => `https://x.com/${handle}`,
23
+ twitter: (handle) => `https://twitter.com/${handle}`,
24
+ github: (handle) => `https://github.com/${handle}`,
25
+ linkedin: (handle) => `https://www.linkedin.com/in/${handle}/`,
26
+ stackoverflow: (userId) => `https://stackoverflow.com/users/${userId}`,
27
+ };
28
+ function normalizeSocialEntry([platform, value]) {
29
+ const normalizer = PredefinedPlatformNormalizers[platform.toLowerCase()];
30
+ const isAbsoluteUrl = value.startsWith('http://') || value.startsWith('https://');
31
+ if (isAbsoluteUrl) {
32
+ return [platform, value];
33
+ }
34
+ else if (value.includes('/')) {
35
+ throw new Error(`Author socials should be usernames/userIds/handles, or fully qualified HTTP(s) absolute URLs.
36
+ Social platform '${platform}' has illegal value '${value}'`);
37
+ }
38
+ if (normalizer && !isAbsoluteUrl) {
39
+ const normalizedPlatform = platform.toLowerCase();
40
+ const normalizedValue = normalizer(value);
41
+ return [normalizedPlatform, normalizedValue];
42
+ }
43
+ return [platform, value];
44
+ }
45
+ const normalizeSocials = (socials) => {
46
+ return Object.fromEntries(Object.entries(socials).map(normalizeSocialEntry));
47
+ };
48
+ exports.normalizeSocials = normalizeSocials;
@@ -8,12 +8,14 @@ exports.validateBlogPostFrontMatter = validateBlogPostFrontMatter;
8
8
  * LICENSE file in the root directory of this source tree.
9
9
  */
10
10
  const utils_validation_1 = require("@docusaurus/utils-validation");
11
+ const authorsSocials_1 = require("./authorsSocials");
11
12
  const BlogPostFrontMatterAuthorSchema = utils_validation_1.JoiFrontMatter.object({
12
13
  key: utils_validation_1.JoiFrontMatter.string(),
13
14
  name: utils_validation_1.JoiFrontMatter.string(),
14
15
  title: utils_validation_1.JoiFrontMatter.string(),
15
16
  url: utils_validation_1.URISchema,
16
17
  imageURL: utils_validation_1.JoiFrontMatter.string(),
18
+ socials: authorsSocials_1.AuthorSocialsSchema,
17
19
  })
18
20
  .or('key', 'name', 'imageURL')
19
21
  .rename('image_url', 'imageURL', { alias: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-blog",
3
- "version": "0.0.0-5994",
3
+ "version": "0.0.0-5995",
4
4
  "description": "Blog plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/plugin-content-blog.d.ts",
@@ -31,13 +31,13 @@
31
31
  },
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@docusaurus/core": "0.0.0-5994",
35
- "@docusaurus/logger": "0.0.0-5994",
36
- "@docusaurus/mdx-loader": "0.0.0-5994",
37
- "@docusaurus/types": "0.0.0-5994",
38
- "@docusaurus/utils": "0.0.0-5994",
39
- "@docusaurus/utils-common": "0.0.0-5994",
40
- "@docusaurus/utils-validation": "0.0.0-5994",
34
+ "@docusaurus/core": "0.0.0-5995",
35
+ "@docusaurus/logger": "0.0.0-5995",
36
+ "@docusaurus/mdx-loader": "0.0.0-5995",
37
+ "@docusaurus/types": "0.0.0-5995",
38
+ "@docusaurus/utils": "0.0.0-5995",
39
+ "@docusaurus/utils-common": "0.0.0-5995",
40
+ "@docusaurus/utils-validation": "0.0.0-5995",
41
41
  "cheerio": "^1.0.0-rc.12",
42
42
  "feed": "^4.2.2",
43
43
  "fs-extra": "^11.1.1",
@@ -59,5 +59,5 @@
59
59
  "devDependencies": {
60
60
  "@total-typescript/shoehorn": "^0.1.2"
61
61
  },
62
- "gitHead": "4905b76b4b39c2f102bbc78d018933f57ea39b78"
62
+ "gitHead": "c12bf10b9832a94916891f384814d62c4f49fd34"
63
63
  }
package/src/authors.ts CHANGED
@@ -5,8 +5,10 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import * as _ from 'lodash';
8
9
  import {getDataFileData, normalizeUrl} from '@docusaurus/utils';
9
10
  import {Joi, URISchema} from '@docusaurus/utils-validation';
11
+ import {AuthorSocialsSchema, normalizeSocials} from './authorsSocials';
10
12
  import type {BlogContentPaths} from './types';
11
13
  import type {
12
14
  Author,
@@ -20,12 +22,13 @@ export type AuthorsMap = {[authorKey: string]: Author};
20
22
  const AuthorsMapSchema = Joi.object<AuthorsMap>()
21
23
  .pattern(
22
24
  Joi.string(),
23
- Joi.object({
25
+ Joi.object<Author>({
24
26
  name: Joi.string(),
25
27
  url: URISchema,
26
28
  imageURL: URISchema,
27
29
  title: Joi.string(),
28
30
  email: Joi.string(),
31
+ socials: AuthorSocialsSchema,
29
32
  })
30
33
  .rename('image_url', 'imageURL')
31
34
  .or('name', 'imageURL')
@@ -51,18 +54,32 @@ export function validateAuthorsMap(content: unknown): AuthorsMap {
51
54
  return value;
52
55
  }
53
56
 
57
+ function normalizeAuthor(author: Author): Author {
58
+ return {
59
+ ...author,
60
+ socials: author.socials ? normalizeSocials(author.socials) : undefined,
61
+ };
62
+ }
63
+
64
+ function normalizeAuthorsMap(authorsMap: AuthorsMap): AuthorsMap {
65
+ return _.mapValues(authorsMap, normalizeAuthor);
66
+ }
67
+
54
68
  export async function getAuthorsMap(params: {
55
69
  authorsMapPath: string;
56
70
  contentPaths: BlogContentPaths;
57
71
  }): Promise<AuthorsMap | undefined> {
58
- return getDataFileData(
72
+ const authorsMap = await getDataFileData(
59
73
  {
60
74
  filePath: params.authorsMapPath,
61
75
  contentPaths: params.contentPaths,
62
76
  fileType: 'authors map',
63
77
  },
78
+ // TODO annoying to test: tightly coupled FS reads + validation...
64
79
  validateAuthorsMap,
65
80
  );
81
+
82
+ return authorsMap ? normalizeAuthorsMap(authorsMap) : undefined;
66
83
  }
67
84
 
68
85
  type AuthorsParam = {
@@ -115,7 +132,7 @@ function getFrontMatterAuthorLegacy({
115
132
  function normalizeFrontMatterAuthors(
116
133
  frontMatterAuthors: BlogPostFrontMatterAuthors = [],
117
134
  ): BlogPostFrontMatterAuthor[] {
118
- function normalizeAuthor(
135
+ function normalizeFrontMatterAuthor(
119
136
  authorInput: string | Author,
120
137
  ): BlogPostFrontMatterAuthor {
121
138
  if (typeof authorInput === 'string') {
@@ -128,8 +145,8 @@ function normalizeFrontMatterAuthors(
128
145
  }
129
146
 
130
147
  return Array.isArray(frontMatterAuthors)
131
- ? frontMatterAuthors.map(normalizeAuthor)
132
- : [normalizeAuthor(frontMatterAuthors)];
148
+ ? frontMatterAuthors.map(normalizeFrontMatterAuthor)
149
+ : [normalizeFrontMatterAuthor(frontMatterAuthors)];
133
150
  }
134
151
 
135
152
  function getFrontMatterAuthors(params: AuthorsParam): Author[] {
@@ -158,11 +175,11 @@ ${Object.keys(authorsMap)
158
175
  }
159
176
 
160
177
  function toAuthor(frontMatterAuthor: BlogPostFrontMatterAuthor): Author {
161
- return {
178
+ return normalizeAuthor({
162
179
  // Author def from authorsMap can be locally overridden by front matter
163
180
  ...getAuthorsMapAuthor(frontMatterAuthor.key),
164
181
  ...frontMatterAuthor,
165
- };
182
+ });
166
183
  }
167
184
 
168
185
  return frontMatterAuthors.map(toAuthor);
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import {Joi} from '@docusaurus/utils-validation';
9
+
10
+ import type {
11
+ AuthorSocials,
12
+ SocialPlatformKey,
13
+ } from '@docusaurus/plugin-content-blog';
14
+
15
+ export const AuthorSocialsSchema = Joi.object<AuthorSocials>({
16
+ twitter: Joi.string(),
17
+ github: Joi.string(),
18
+ linkedin: Joi.string(),
19
+ // StackOverflow userIds like '82609' are parsed as numbers by Yaml
20
+ stackoverflow: Joi.alternatives()
21
+ .try(Joi.number(), Joi.string())
22
+ .custom((val) => String(val)),
23
+ x: Joi.string(),
24
+ }).unknown();
25
+
26
+ type PredefinedPlatformNormalizer = (value: string) => string;
27
+
28
+ const PredefinedPlatformNormalizers: Record<
29
+ SocialPlatformKey | string,
30
+ PredefinedPlatformNormalizer
31
+ > = {
32
+ x: (handle: string) => `https://x.com/${handle}`,
33
+ twitter: (handle: string) => `https://twitter.com/${handle}`,
34
+ github: (handle: string) => `https://github.com/${handle}`,
35
+ linkedin: (handle: string) => `https://www.linkedin.com/in/${handle}/`,
36
+ stackoverflow: (userId: string) =>
37
+ `https://stackoverflow.com/users/${userId}`,
38
+ };
39
+
40
+ type SocialEntry = [string, string];
41
+
42
+ function normalizeSocialEntry([platform, value]: SocialEntry): SocialEntry {
43
+ const normalizer = PredefinedPlatformNormalizers[platform.toLowerCase()];
44
+ const isAbsoluteUrl =
45
+ value.startsWith('http://') || value.startsWith('https://');
46
+ if (isAbsoluteUrl) {
47
+ return [platform, value];
48
+ } else if (value.includes('/')) {
49
+ throw new Error(
50
+ `Author socials should be usernames/userIds/handles, or fully qualified HTTP(s) absolute URLs.
51
+ Social platform '${platform}' has illegal value '${value}'`,
52
+ );
53
+ }
54
+ if (normalizer && !isAbsoluteUrl) {
55
+ const normalizedPlatform = platform.toLowerCase();
56
+ const normalizedValue = normalizer(value);
57
+ return [normalizedPlatform as SocialPlatformKey, normalizedValue];
58
+ }
59
+ return [platform, value];
60
+ }
61
+
62
+ export const normalizeSocials = (socials: AuthorSocials): AuthorSocials => {
63
+ return Object.fromEntries(Object.entries(socials).map(normalizeSocialEntry));
64
+ };
@@ -13,6 +13,7 @@ import {
13
13
  URISchema,
14
14
  validateFrontMatter,
15
15
  } from '@docusaurus/utils-validation';
16
+ import {AuthorSocialsSchema} from './authorsSocials';
16
17
  import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
17
18
 
18
19
  const BlogPostFrontMatterAuthorSchema = Joi.object({
@@ -21,6 +22,7 @@ const BlogPostFrontMatterAuthorSchema = Joi.object({
21
22
  title: Joi.string(),
22
23
  url: URISchema,
23
24
  imageURL: Joi.string(),
25
+ socials: AuthorSocialsSchema,
24
26
  })
25
27
  .or('key', 'name', 'imageURL')
26
28
  .rename('image_url', 'imageURL', {alias: true});
@@ -43,6 +43,29 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
43
43
  authorsImageUrls: (string | undefined)[];
44
44
  };
45
45
 
46
+ /**
47
+ * Note we don't pre-define all possible platforms
48
+ * Users can add their own custom platforms if needed
49
+ */
50
+ export type SocialPlatformKey =
51
+ | 'twitter'
52
+ | 'github'
53
+ | 'linkedin'
54
+ | 'stackoverflow'
55
+ | 'x';
56
+
57
+ /**
58
+ * Social platforms of the author.
59
+ * The record value is usually the fully qualified link of the social profile.
60
+ * For pre-defined platforms, it's possible to pass a handle instead
61
+ */
62
+ export type AuthorSocials = Partial<Record<SocialPlatformKey, string>> & {
63
+ /**
64
+ * Unknown keys are allowed: users can pass additional social platforms
65
+ */
66
+ [customAuthorSocialPlatform: string]: string;
67
+ };
68
+
46
69
  export type Author = {
47
70
  key?: string; // TODO temporary, need refactor
48
71
 
@@ -69,11 +92,15 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
69
92
  * to generate a fallback `mailto:` URL.
70
93
  */
71
94
  email?: string;
95
+ /**
96
+ * Social platforms of the author
97
+ * Usually displayed as a list of social icon links.
98
+ */
99
+ socials?: AuthorSocials;
72
100
  /**
73
101
  * Unknown keys are allowed, so that we can pass custom fields to authors,
74
- * e.g., `twitter`.
75
102
  */
76
- [key: string]: unknown;
103
+ [customAuthorAttribute: string]: unknown;
77
104
  };
78
105
 
79
106
  /**