@azerion/bunosaurus-plugin-content-docs 0.0.0-stage → 4.0.0

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.
Files changed (119) hide show
  1. package/README.md +6 -2
  2. package/lib/categoryGeneratedIndex.d.ts +12 -0
  3. package/lib/categoryGeneratedIndex.js +36 -0
  4. package/lib/cli.d.ts +13 -0
  5. package/lib/cli.js +124 -0
  6. package/lib/client/doc.d.ts +29 -0
  7. package/lib/client/doc.js +47 -0
  8. package/lib/client/docSidebarItemsExpandedState.d.ts +30 -0
  9. package/lib/client/docSidebarItemsExpandedState.js +27 -0
  10. package/lib/client/docsClientUtils.d.ts +15 -0
  11. package/lib/client/docsClientUtils.js +86 -0
  12. package/lib/client/docsPreferredVersion.d.ts +29 -0
  13. package/lib/client/docsPreferredVersion.js +124 -0
  14. package/lib/client/docsSearch.d.ts +19 -0
  15. package/lib/client/docsSearch.js +39 -0
  16. package/lib/client/docsSidebar.d.ts +25 -0
  17. package/lib/client/docsSidebar.js +29 -0
  18. package/lib/client/docsUtils.d.ts +112 -0
  19. package/lib/client/docsUtils.js +299 -0
  20. package/lib/client/docsVersion.d.ts +19 -0
  21. package/lib/client/docsVersion.js +25 -0
  22. package/lib/client/index.d.ts +91 -0
  23. package/lib/client/index.js +83 -0
  24. package/lib/client/structuredDataUtils.d.ts +11 -0
  25. package/lib/client/structuredDataUtils.js +35 -0
  26. package/lib/constants.d.ts +14 -0
  27. package/lib/constants.js +17 -0
  28. package/lib/contentHelpers.d.ts +12 -0
  29. package/lib/contentHelpers.js +31 -0
  30. package/lib/docs.d.ts +48 -0
  31. package/lib/docs.js +252 -0
  32. package/lib/frontMatter.d.ts +10 -0
  33. package/lib/frontMatter.js +46 -0
  34. package/lib/globalData.d.ts +9 -0
  35. package/lib/globalData.js +59 -0
  36. package/lib/index.d.ts +10 -0
  37. package/lib/index.js +198 -0
  38. package/lib/numberPrefix.d.ts +11 -0
  39. package/lib/numberPrefix.js +50 -0
  40. package/lib/options.d.ts +10 -0
  41. package/lib/options.js +138 -0
  42. package/lib/props.d.ts +21 -0
  43. package/lib/props.js +156 -0
  44. package/lib/routes.d.ts +22 -0
  45. package/lib/routes.js +184 -0
  46. package/lib/server-export.d.ts +9 -0
  47. package/lib/server-export.js +25 -0
  48. package/lib/sidebars/generator.d.ts +10 -0
  49. package/lib/sidebars/generator.js +217 -0
  50. package/lib/sidebars/index.d.ts +13 -0
  51. package/lib/sidebars/index.js +99 -0
  52. package/lib/sidebars/normalization.d.ts +13 -0
  53. package/lib/sidebars/normalization.js +58 -0
  54. package/lib/sidebars/postProcessor.d.ts +11 -0
  55. package/lib/sidebars/postProcessor.js +82 -0
  56. package/lib/sidebars/processor.d.ts +10 -0
  57. package/lib/sidebars/processor.js +77 -0
  58. package/lib/sidebars/types.d.ts +192 -0
  59. package/lib/sidebars/types.js +8 -0
  60. package/lib/sidebars/utils.d.ts +69 -0
  61. package/lib/sidebars/utils.js +327 -0
  62. package/lib/sidebars/validation.d.ts +11 -0
  63. package/lib/sidebars/validation.js +152 -0
  64. package/lib/slug.d.ts +15 -0
  65. package/lib/slug.js +51 -0
  66. package/lib/translations.d.ts +10 -0
  67. package/lib/translations.js +243 -0
  68. package/lib/types.d.ts +27 -0
  69. package/lib/types.js +8 -0
  70. package/lib/versions/files.d.ts +54 -0
  71. package/lib/versions/files.js +152 -0
  72. package/lib/versions/loadVersion.d.ts +17 -0
  73. package/lib/versions/loadVersion.js +126 -0
  74. package/lib/versions/validation.d.ts +17 -0
  75. package/lib/versions/validation.js +70 -0
  76. package/lib/versions/version.d.ts +40 -0
  77. package/lib/versions/version.js +189 -0
  78. package/package.json +70 -4
  79. package/src/categoryGeneratedIndex.ts +60 -0
  80. package/src/cli.ts +180 -0
  81. package/src/client/doc.tsx +71 -0
  82. package/src/client/docSidebarItemsExpandedState.tsx +55 -0
  83. package/src/client/docsClientUtils.ts +140 -0
  84. package/src/client/docsPreferredVersion.tsx +245 -0
  85. package/src/client/docsSearch.test.ts +15 -0
  86. package/src/client/docsSearch.ts +57 -0
  87. package/src/client/docsSidebar.tsx +50 -0
  88. package/src/client/docsUtils.tsx +442 -0
  89. package/src/client/docsVersion.tsx +36 -0
  90. package/src/client/index.ts +211 -0
  91. package/src/client/structuredDataUtils.ts +54 -0
  92. package/src/constants.ts +15 -0
  93. package/src/contentHelpers.ts +34 -0
  94. package/src/docs.ts +402 -0
  95. package/src/frontMatter.ts +57 -0
  96. package/src/globalData.ts +79 -0
  97. package/src/index.ts +289 -0
  98. package/src/numberPrefix.ts +62 -0
  99. package/src/options.ts +185 -0
  100. package/src/plugin-content-docs.d.ts +667 -0
  101. package/src/props.ts +223 -0
  102. package/src/routes.ts +263 -0
  103. package/src/server-export.ts +26 -0
  104. package/src/sidebars/README.md +10 -0
  105. package/src/sidebars/generator.ts +307 -0
  106. package/src/sidebars/index.ts +130 -0
  107. package/src/sidebars/normalization.ts +91 -0
  108. package/src/sidebars/postProcessor.ts +115 -0
  109. package/src/sidebars/processor.ts +122 -0
  110. package/src/sidebars/types.ts +293 -0
  111. package/src/sidebars/utils.ts +529 -0
  112. package/src/sidebars/validation.ts +189 -0
  113. package/src/slug.ts +79 -0
  114. package/src/translations.ts +365 -0
  115. package/src/types.ts +34 -0
  116. package/src/versions/files.ts +240 -0
  117. package/src/versions/loadVersion.ts +185 -0
  118. package/src/versions/validation.ts +115 -0
  119. package/src/versions/version.ts +300 -0
@@ -0,0 +1,240 @@
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 path from 'node:path';
9
+ import {
10
+ getPluginI18nPath,
11
+ getLocaleConfig,
12
+ DEFAULT_PLUGIN_ID,
13
+ } from '@docusaurus/utils';
14
+ import {pathExists, readJSON} from '@docusaurus/fs';
15
+ import {
16
+ VERSIONS_JSON_FILE,
17
+ VERSIONED_DOCS_DIR,
18
+ VERSIONED_SIDEBARS_DIR,
19
+ CURRENT_VERSION_NAME,
20
+ } from '../constants';
21
+ import {validateVersionNames} from './validation';
22
+ import type {
23
+ PluginOptions,
24
+ VersionMetadata,
25
+ } from '@docusaurus/plugin-content-docs';
26
+ import type {VersionContext} from './version';
27
+
28
+ /** Add a prefix like `community_version-1.0.0`. No-op for default instance. */
29
+ function addPluginIdPrefix(fileOrDir: string, pluginId: string): string {
30
+ return pluginId === DEFAULT_PLUGIN_ID
31
+ ? fileOrDir
32
+ : `${pluginId}_${fileOrDir}`;
33
+ }
34
+
35
+ /** `[siteDir]/community_versioned_docs/version-1.0.0` */
36
+ export function getVersionDocsDirPath(
37
+ siteDir: string,
38
+ pluginId: string,
39
+ versionName: string,
40
+ ): string {
41
+ return path.join(
42
+ siteDir,
43
+ addPluginIdPrefix(VERSIONED_DOCS_DIR, pluginId),
44
+ `version-${versionName}`,
45
+ );
46
+ }
47
+
48
+ /** `[siteDir]/community_versioned_sidebars/version-1.0.0-sidebars.json` */
49
+ export function getVersionSidebarsPath(
50
+ siteDir: string,
51
+ pluginId: string,
52
+ versionName: string,
53
+ ): string {
54
+ return path.join(
55
+ siteDir,
56
+ addPluginIdPrefix(VERSIONED_SIDEBARS_DIR, pluginId),
57
+ `version-${versionName}-sidebars.json`,
58
+ );
59
+ }
60
+
61
+ export function getDocsDirPathLocalized({
62
+ localizationDir,
63
+ pluginId,
64
+ versionName,
65
+ }: {
66
+ localizationDir: string;
67
+ pluginId: string;
68
+ versionName: string;
69
+ }): string {
70
+ return getPluginI18nPath({
71
+ localizationDir,
72
+ pluginName: 'docusaurus-plugin-content-docs',
73
+ pluginId,
74
+ subPaths: [
75
+ versionName === CURRENT_VERSION_NAME
76
+ ? CURRENT_VERSION_NAME
77
+ : `version-${versionName}`,
78
+ ],
79
+ });
80
+ }
81
+
82
+ export function getPluginDirPathLocalized({
83
+ localizationDir,
84
+ pluginId,
85
+ }: {
86
+ localizationDir: string;
87
+ pluginId: string;
88
+ }): string {
89
+ return getPluginI18nPath({
90
+ localizationDir,
91
+ pluginName: 'docusaurus-plugin-content-docs',
92
+ pluginId,
93
+ subPaths: [],
94
+ });
95
+ }
96
+
97
+ /** `community` => `[siteDir]/community_versions.json` */
98
+ export function getVersionsFilePath(siteDir: string, pluginId: string): string {
99
+ return path.join(siteDir, addPluginIdPrefix(VERSIONS_JSON_FILE, pluginId));
100
+ }
101
+
102
+ /**
103
+ * Reads the plugin's respective `versions.json` file, and returns its content.
104
+ *
105
+ * @throws Throws if validation fails, i.e. `versions.json` doesn't contain an
106
+ * array of valid version names.
107
+ */
108
+ export async function readVersionsFile(
109
+ siteDir: string,
110
+ pluginId: string,
111
+ ): Promise<string[] | null> {
112
+ const versionsFilePath = getVersionsFilePath(siteDir, pluginId);
113
+ if (await pathExists(versionsFilePath)) {
114
+ const content: unknown = await readJSON(versionsFilePath);
115
+ validateVersionNames(content);
116
+ return content;
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Reads the `versions.json` file, and returns an ordered list of version names.
123
+ *
124
+ * - If `disableVersioning` is turned on, it will return `["current"]` (requires
125
+ * `includeCurrentVersion` to be true);
126
+ * - If `includeCurrentVersion` is turned on, "current" will be inserted at the
127
+ * beginning, if not already there.
128
+ *
129
+ * You need to use {@link filterVersions} after this.
130
+ *
131
+ * @throws Throws an error if `disableVersioning: true` but `versions.json`
132
+ * doesn't exist (i.e. site is not versioned)
133
+ * @throws Throws an error if versions list is empty (empty `versions.json` or
134
+ * `disableVersioning` is true, and not including current version)
135
+ */
136
+ export async function readVersionNames(
137
+ siteDir: string,
138
+ options: PluginOptions,
139
+ ): Promise<string[]> {
140
+ const versionFileContent = await readVersionsFile(siteDir, options.id);
141
+
142
+ if (!versionFileContent && options.disableVersioning) {
143
+ throw new Error(
144
+ `Docs: using "disableVersioning: true" option on a non-versioned site does not make sense.`,
145
+ );
146
+ }
147
+
148
+ const versions = options.disableVersioning ? [] : (versionFileContent ?? []);
149
+
150
+ // We add the current version at the beginning, unless:
151
+ // - user don't want to; or
152
+ // - it's already been explicitly added to versions.json
153
+ if (
154
+ options.includeCurrentVersion &&
155
+ !versions.includes(CURRENT_VERSION_NAME)
156
+ ) {
157
+ versions.unshift(CURRENT_VERSION_NAME);
158
+ }
159
+
160
+ if (versions.length === 0) {
161
+ throw new Error(
162
+ `It is not possible to use docs without any version. No version is included because you have requested to not include ${path.resolve(
163
+ options.path,
164
+ )} through "includeCurrentVersion: false", while ${
165
+ options.disableVersioning
166
+ ? 'versioning is disabled with "disableVersioning: true"'
167
+ : `the versions file is empty/non-existent`
168
+ }.`,
169
+ );
170
+ }
171
+
172
+ return versions;
173
+ }
174
+
175
+ /**
176
+ * Gets the path-related version metadata.
177
+ *
178
+ * @throws Throws if the resolved docs folder or sidebars file doesn't exist.
179
+ * Does not throw if a versioned sidebar is missing (since we don't create empty
180
+ * files).
181
+ */
182
+ export async function getVersionMetadataPaths({
183
+ versionName,
184
+ context,
185
+ options,
186
+ }: VersionContext): Promise<
187
+ Pick<
188
+ VersionMetadata,
189
+ 'contentPath' | 'contentPathLocalized' | 'sidebarFilePath'
190
+ >
191
+ > {
192
+ const isCurrent = versionName === CURRENT_VERSION_NAME;
193
+
194
+ const shouldTranslate = getLocaleConfig(context.i18n).translate;
195
+ const contentPathLocalized = shouldTranslate
196
+ ? getDocsDirPathLocalized({
197
+ localizationDir: context.localizationDir,
198
+ pluginId: options.id,
199
+ versionName,
200
+ })
201
+ : undefined;
202
+
203
+ const contentPath = isCurrent
204
+ ? path.resolve(context.siteDir, options.path)
205
+ : getVersionDocsDirPath(context.siteDir, options.id, versionName);
206
+ const sidebarFilePath = isCurrent
207
+ ? options.sidebarPath
208
+ : getVersionSidebarsPath(context.siteDir, options.id, versionName);
209
+
210
+ if (!(await pathExists(contentPath))) {
211
+ throw new Error(
212
+ `The docs folder does not exist for version "${versionName}". A docs folder is expected to be found at ${path.relative(
213
+ context.siteDir,
214
+ contentPath,
215
+ )}.`,
216
+ );
217
+ }
218
+
219
+ // If the current version defines a path to a sidebar file that does not
220
+ // exist, we throw! Note: for versioned sidebars, the file may not exist (as
221
+ // we prefer to not create it rather than to create an empty file)
222
+ // See https://github.com/facebook/docusaurus/issues/3366
223
+ // See https://github.com/facebook/docusaurus/pull/4775
224
+ if (
225
+ versionName === CURRENT_VERSION_NAME &&
226
+ typeof sidebarFilePath === 'string' &&
227
+ !(await pathExists(sidebarFilePath))
228
+ ) {
229
+ throw new Error(`The path to the sidebar file does not exist at "${path.relative(
230
+ context.siteDir,
231
+ sidebarFilePath,
232
+ )}".
233
+ Please set the docs "sidebarPath" field in your config file to:
234
+ - a sidebars path that exists
235
+ - false: to disable the sidebar
236
+ - undefined: for Docusaurus to generate it automatically`);
237
+ }
238
+
239
+ return {contentPath, contentPathLocalized, sidebarFilePath};
240
+ }
@@ -0,0 +1,185 @@
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 path from 'node:path';
9
+ import _ from 'lodash';
10
+ import {aliasedSitePathToRelativePath, createSlugger} from '@docusaurus/utils';
11
+ import {getTagsFile} from '@docusaurus/utils-validation';
12
+ import logger from '@docusaurus/logger';
13
+ import {
14
+ addDocNavigation,
15
+ createDocsByIdIndex,
16
+ type DocEnv,
17
+ processDocMetadata,
18
+ readVersionDocs,
19
+ } from '../docs';
20
+ import {loadSidebars} from '../sidebars';
21
+ import {createSidebarsUtils} from '../sidebars/utils';
22
+ import type {TagsFile} from '@docusaurus/utils';
23
+ import type {
24
+ DocMetadataBase,
25
+ LoadedVersion,
26
+ PluginOptions,
27
+ VersionMetadata,
28
+ } from '@docusaurus/plugin-content-docs';
29
+ import type {DocFile} from '../types';
30
+ import type {LoadContext} from '@docusaurus/types';
31
+
32
+ type LoadVersionParams = {
33
+ context: LoadContext;
34
+ options: PluginOptions;
35
+ versionMetadata: VersionMetadata;
36
+ env: DocEnv;
37
+ };
38
+
39
+ function ensureNoDuplicateDocId(docs: DocMetadataBase[]): void {
40
+ const duplicatesById = _.chain(docs)
41
+ .sort((d1, d2) => {
42
+ // Need to sort because glob order is non-deterministic
43
+ // TODO maybe we should create a deterministic glob utils?
44
+ // see https://github.com/sindresorhus/globby/issues/131
45
+ return d1.source.localeCompare(d2.source);
46
+ })
47
+ .groupBy((d) => d.id)
48
+ .pickBy((group) => group.length > 1)
49
+ .value();
50
+
51
+ const duplicateIdEntries = Object.entries(duplicatesById);
52
+
53
+ if (duplicateIdEntries.length) {
54
+ const idMessages = duplicateIdEntries
55
+ .map(([id, duplicateDocs]) => {
56
+ return logger.interpolate`- code=${id} found in number=${
57
+ duplicateDocs.length
58
+ } docs:
59
+ - ${duplicateDocs
60
+ .map((d) => aliasedSitePathToRelativePath(d.source))
61
+ .join('\n - ')}`;
62
+ })
63
+ .join('\n\n');
64
+
65
+ const message = `The docs plugin found docs sharing the same id:
66
+ \n${idMessages}\n
67
+ Docs should have distinct ids.
68
+ In case of conflict, you can rename the docs file, or use the ${logger.code(
69
+ 'id',
70
+ )} front matter to assign an explicit distinct id to each doc.
71
+ `;
72
+
73
+ throw new Error(message);
74
+ }
75
+ }
76
+
77
+ async function loadVersionDocsBase({
78
+ tagsFile,
79
+ context,
80
+ options,
81
+ versionMetadata,
82
+ env,
83
+ }: LoadVersionParams & {
84
+ tagsFile: TagsFile | null;
85
+ }): Promise<DocMetadataBase[]> {
86
+ const docFiles = await readVersionDocs(versionMetadata, options);
87
+ if (docFiles.length === 0) {
88
+ throw new Error(
89
+ `Docs version "${
90
+ versionMetadata.versionName
91
+ }" has no docs! At least one doc should exist at "${path.relative(
92
+ context.siteDir,
93
+ versionMetadata.contentPath,
94
+ )}".`,
95
+ );
96
+ }
97
+ function processVersionDoc(docFile: DocFile) {
98
+ return processDocMetadata({
99
+ docFile,
100
+ versionMetadata,
101
+ context,
102
+ options,
103
+ env,
104
+ tagsFile,
105
+ });
106
+ }
107
+ const docs = await Promise.all(docFiles.map(processVersionDoc));
108
+ ensureNoDuplicateDocId(docs);
109
+ return docs;
110
+ }
111
+
112
+ async function doLoadVersion({
113
+ context,
114
+ options,
115
+ versionMetadata,
116
+ env,
117
+ }: LoadVersionParams): Promise<LoadedVersion> {
118
+ const tagsFile = await getTagsFile({
119
+ contentPaths: versionMetadata,
120
+ tags: options.tags,
121
+ });
122
+
123
+ const docsBase: DocMetadataBase[] = await loadVersionDocsBase({
124
+ tagsFile,
125
+ context,
126
+ options,
127
+ versionMetadata,
128
+ env,
129
+ });
130
+
131
+ // TODO we only ever need draftIds in further code, not full draft items
132
+ // To simplify and prevent mistakes, avoid exposing draft
133
+ // replace draft=>draftIds in content loaded
134
+ const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft);
135
+
136
+ const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
137
+ sidebarItemsGenerator: options.sidebarItemsGenerator,
138
+ numberPrefixParser: options.numberPrefixParser,
139
+ docs,
140
+ drafts,
141
+ version: versionMetadata,
142
+ sidebarOptions: {
143
+ sidebarCollapsed: options.sidebarCollapsed,
144
+ sidebarCollapsible: options.sidebarCollapsible,
145
+ },
146
+ categoryLabelSlugger: createSlugger(),
147
+ });
148
+
149
+ const sidebarsUtils = createSidebarsUtils(sidebars);
150
+
151
+ const docsById = createDocsByIdIndex(docs);
152
+ const allDocIds = Object.keys(docsById);
153
+
154
+ sidebarsUtils.checkLegacyVersionedSidebarNames({
155
+ sidebarFilePath: versionMetadata.sidebarFilePath as string,
156
+ versionMetadata,
157
+ });
158
+ sidebarsUtils.checkSidebarsDocIds({
159
+ allDocIds,
160
+ sidebarFilePath: versionMetadata.sidebarFilePath as string,
161
+ versionMetadata,
162
+ });
163
+
164
+ return {
165
+ ...versionMetadata,
166
+ docs: addDocNavigation({
167
+ docs,
168
+ sidebarsUtils,
169
+ }),
170
+ drafts,
171
+ sidebars,
172
+ };
173
+ }
174
+
175
+ export async function loadVersion(
176
+ params: LoadVersionParams,
177
+ ): Promise<LoadedVersion> {
178
+ try {
179
+ return await doLoadVersion(params);
180
+ } catch (err) {
181
+ // TODO use error cause (but need to refactor many tests)
182
+ logger.error`Loading of version failed for version name=${params.versionMetadata.versionName}`;
183
+ throw err;
184
+ }
185
+ }
@@ -0,0 +1,115 @@
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 _ from 'lodash';
9
+ import type {VersionsOptions} from '@docusaurus/plugin-content-docs';
10
+
11
+ export function validateVersionName(name: unknown): asserts name is string {
12
+ if (typeof name !== 'string') {
13
+ throw new Error(
14
+ `Versions should be strings. Found type "${typeof name}" for version ${JSON.stringify(
15
+ name,
16
+ )}.`,
17
+ );
18
+ }
19
+ if (!name.trim()) {
20
+ throw new Error(
21
+ `Invalid version name "${name}": version name must contain at least one non-whitespace character.`,
22
+ );
23
+ }
24
+ const errors: [RegExp, string][] = [
25
+ [/[/\\]/, 'should not include slash (/) or backslash (\\)'],
26
+ [/.{33,}/, 'cannot be longer than 32 characters'],
27
+ // eslint-disable-next-line no-control-regex
28
+ [/[<>:"|?*\x00-\x1F]/, 'should be a valid file path'],
29
+ [/^\.\.?$/, 'should not be "." or ".."'],
30
+ ];
31
+
32
+ errors.forEach(([pattern, message]) => {
33
+ if (pattern.test(name)) {
34
+ throw new Error(
35
+ `Invalid version name "${name}": version name ${message}.`,
36
+ );
37
+ }
38
+ });
39
+ }
40
+
41
+ export function validateVersionNames(
42
+ names: unknown,
43
+ ): asserts names is string[] {
44
+ if (!Array.isArray(names)) {
45
+ throw new Error(
46
+ `The versions file should contain an array of version names! Found content: ${JSON.stringify(
47
+ names,
48
+ )}`,
49
+ );
50
+ }
51
+
52
+ names.forEach(validateVersionName);
53
+ }
54
+
55
+ /**
56
+ * @throws Throws for one of the following invalid options:
57
+ * - `lastVersion` is non-existent
58
+ * - `versions` includes unknown keys
59
+ * - `onlyIncludeVersions` is empty, contains unknown names, or doesn't include
60
+ * `latestVersion` (if provided)
61
+ */
62
+ export function validateVersionsOptions(
63
+ availableVersionNames: string[],
64
+ options: VersionsOptions,
65
+ ): void {
66
+ const availableVersionNamesMsg = `Available version names are: ${availableVersionNames.join(
67
+ ', ',
68
+ )}`;
69
+ if (
70
+ options.lastVersion &&
71
+ !availableVersionNames.includes(options.lastVersion)
72
+ ) {
73
+ throw new Error(
74
+ `Docs option lastVersion: ${options.lastVersion} is invalid. ${availableVersionNamesMsg}`,
75
+ );
76
+ }
77
+ const unknownVersionConfigNames = _.difference(
78
+ Object.keys(options.versions),
79
+ availableVersionNames,
80
+ );
81
+ if (unknownVersionConfigNames.length > 0) {
82
+ throw new Error(
83
+ `Invalid docs option "versions": unknown versions (${unknownVersionConfigNames.join(
84
+ ',',
85
+ )}) found. ${availableVersionNamesMsg}`,
86
+ );
87
+ }
88
+
89
+ if (options.onlyIncludeVersions) {
90
+ if (options.onlyIncludeVersions.length === 0) {
91
+ throw new Error(
92
+ `Invalid docs option "onlyIncludeVersions": an empty array is not allowed, at least one version is needed.`,
93
+ );
94
+ }
95
+ const unknownOnlyIncludeVersionNames = _.difference(
96
+ options.onlyIncludeVersions,
97
+ availableVersionNames,
98
+ );
99
+ if (unknownOnlyIncludeVersionNames.length > 0) {
100
+ throw new Error(
101
+ `Invalid docs option "onlyIncludeVersions": unknown versions (${unknownOnlyIncludeVersionNames.join(
102
+ ',',
103
+ )}) found. ${availableVersionNamesMsg}`,
104
+ );
105
+ }
106
+ if (
107
+ options.lastVersion &&
108
+ !options.onlyIncludeVersions.includes(options.lastVersion)
109
+ ) {
110
+ throw new Error(
111
+ `Invalid docs option "lastVersion": if you use both the "onlyIncludeVersions" and "lastVersion" options, then "lastVersion" must be present in the provided "onlyIncludeVersions" array.`,
112
+ );
113
+ }
114
+ }
115
+ }