@zeropress/preview-data-validator 0.1.0 → 0.2.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.
- package/README.md +6 -2
- package/package.json +3 -2
- package/src/index.d.ts +19 -18
- package/src/index.js +74 -64
- package/src/preview-data.v0.3.schema.json +218 -0
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# @zeropress/preview-data-validator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Shared validation core for ZeroPress preview data v0.3.
|
|
4
8
|
|
|
5
9
|
This package is the canonical runtime contract for preview payloads consumed by:
|
|
6
10
|
|
|
@@ -27,7 +31,7 @@ import {
|
|
|
27
31
|
Schema export:
|
|
28
32
|
|
|
29
33
|
```js
|
|
30
|
-
import schemaUrl from '@zeropress/preview-data-validator/preview-data.v0.
|
|
34
|
+
import schemaUrl from '@zeropress/preview-data-validator/preview-data.v0.3.schema.json';
|
|
31
35
|
```
|
|
32
36
|
|
|
33
37
|
## API
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeropress/preview-data-validator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared ZeroPress preview data validation core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.js",
|
|
9
|
-
"./preview-data.v0.2.schema.json": "./src/preview-data.v0.2.schema.json"
|
|
9
|
+
"./preview-data.v0.2.schema.json": "./src/preview-data.v0.2.schema.json",
|
|
10
|
+
"./preview-data.v0.3.schema.json": "./src/preview-data.v0.3.schema.json"
|
|
10
11
|
},
|
|
11
12
|
"types": "./src/index.d.ts",
|
|
12
13
|
"files": [
|
package/src/index.d.ts
CHANGED
|
@@ -61,24 +61,28 @@ export interface PreviewTagData {
|
|
|
61
61
|
postCount: number;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export interface
|
|
64
|
+
export interface PreviewPaginatedRouteData {
|
|
65
|
+
path: string;
|
|
66
|
+
page: number;
|
|
67
|
+
totalPages: number;
|
|
65
68
|
posts: string;
|
|
66
69
|
pagination: string;
|
|
67
|
-
categories?: string;
|
|
68
|
-
tags?: string;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
export interface
|
|
72
|
+
export interface PreviewIndexRouteData extends PreviewPaginatedRouteData {
|
|
73
|
+
categories: string;
|
|
74
|
+
tags: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface PreviewArchiveRouteData extends PreviewPaginatedRouteData {}
|
|
78
|
+
|
|
79
|
+
export interface PreviewCategoryRouteData extends PreviewPaginatedRouteData {
|
|
72
80
|
slug: string;
|
|
73
|
-
posts: string;
|
|
74
|
-
pagination: string;
|
|
75
81
|
categories?: string;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
export interface PreviewTagRouteData {
|
|
84
|
+
export interface PreviewTagRouteData extends PreviewPaginatedRouteData {
|
|
79
85
|
slug: string;
|
|
80
|
-
posts: string;
|
|
81
|
-
pagination: string;
|
|
82
86
|
tags?: string;
|
|
83
87
|
}
|
|
84
88
|
|
|
@@ -90,17 +94,14 @@ export interface PreviewContentData {
|
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
export interface PreviewRoutesData {
|
|
93
|
-
index:
|
|
94
|
-
|
|
95
|
-
tags: string;
|
|
96
|
-
};
|
|
97
|
-
archive: PreviewRouteBlocks;
|
|
97
|
+
index: PreviewIndexRouteData[];
|
|
98
|
+
archive: PreviewArchiveRouteData[];
|
|
98
99
|
categories: PreviewCategoryRouteData[];
|
|
99
100
|
tags: PreviewTagRouteData[];
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
export interface
|
|
103
|
-
version: '0.
|
|
103
|
+
export interface PreviewDataV03 {
|
|
104
|
+
version: '0.3';
|
|
104
105
|
generator: string;
|
|
105
106
|
generated_at: string;
|
|
106
107
|
site: PreviewSiteData;
|
|
@@ -114,8 +115,8 @@ export interface PreviewDataValidationResult {
|
|
|
114
115
|
warnings: ValidationIssue[];
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
export const PREVIEW_DATA_VERSION: '0.
|
|
118
|
+
export const PREVIEW_DATA_VERSION: '0.3';
|
|
118
119
|
|
|
119
120
|
export function validatePreviewData(data: unknown): PreviewDataValidationResult;
|
|
120
121
|
export function assertPreviewData<T>(data: T): T;
|
|
121
|
-
export function isPreviewData(data: unknown): data is
|
|
122
|
+
export function isPreviewData(data: unknown): data is PreviewDataV03;
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const PREVIEW_DATA_VERSION = '0.
|
|
1
|
+
export const PREVIEW_DATA_VERSION = '0.3';
|
|
2
2
|
|
|
3
3
|
export function validatePreviewData(data) {
|
|
4
4
|
const errors = [];
|
|
@@ -6,7 +6,7 @@ export function validatePreviewData(data) {
|
|
|
6
6
|
validateClosedObject(data, '', errors, ['version', 'generator', 'generated_at', 'site', 'content', 'routes']);
|
|
7
7
|
|
|
8
8
|
if (!errors.length) {
|
|
9
|
-
validateLiteral(data.version,
|
|
9
|
+
validateLiteral(data.version, PREVIEW_DATA_VERSION, 'version', 'INVALID_VERSION', errors);
|
|
10
10
|
validateNonEmptyString(data.generator, 'generator', 'INVALID_GENERATOR', errors);
|
|
11
11
|
validateDateTimeString(data.generated_at, 'generated_at', 'INVALID_GENERATED_AT', errors);
|
|
12
12
|
|
|
@@ -86,13 +86,11 @@ function validateRoutes(routes, path, errors) {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
allowKeys: ['posts', 'pagination', 'categories', 'tags'],
|
|
89
|
+
validateArray(routes.index, `${path}.index`, 'INVALID_INDEX_ROUTES', errors, (entry, index) => {
|
|
90
|
+
validateIndexRoute(entry, `${path}.index[${index}]`, errors);
|
|
92
91
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
allowKeys: ['posts', 'pagination', 'categories', 'tags'],
|
|
92
|
+
validateArray(routes.archive, `${path}.archive`, 'INVALID_ARCHIVE_ROUTES', errors, (entry, index) => {
|
|
93
|
+
validateArchiveRoute(entry, `${path}.archive[${index}]`, errors);
|
|
96
94
|
});
|
|
97
95
|
validateArray(routes.categories, `${path}.categories`, 'INVALID_CATEGORY_ROUTES', errors, (entry, index) => {
|
|
98
96
|
validateCategoryRoute(entry, `${path}.categories[${index}]`, errors);
|
|
@@ -192,48 +190,61 @@ function validatePreviewTag(tag, path, errors) {
|
|
|
192
190
|
validateInteger(tag.postCount, `${path}.postCount`, 'INVALID_TAG_POST_COUNT', errors, { minimum: 0 });
|
|
193
191
|
}
|
|
194
192
|
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
193
|
+
function validateIndexRoute(route, path, errors) {
|
|
194
|
+
validatePaginatedRoute(route, path, errors, {
|
|
195
|
+
allowedKeys: ['path', 'page', 'totalPages', 'posts', 'pagination', 'categories', 'tags'],
|
|
196
|
+
requiredKeys: ['path', 'page', 'totalPages', 'posts', 'pagination', 'categories', 'tags'],
|
|
197
|
+
routeCodePrefix: 'INDEX_ROUTE',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
201
|
+
function validateArchiveRoute(route, path, errors) {
|
|
202
|
+
validatePaginatedRoute(route, path, errors, {
|
|
203
|
+
allowedKeys: ['path', 'page', 'totalPages', 'posts', 'pagination'],
|
|
204
|
+
requiredKeys: ['path', 'page', 'totalPages', 'posts', 'pagination'],
|
|
205
|
+
routeCodePrefix: 'ARCHIVE_ROUTE',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function validateCategoryRoute(route, path, errors) {
|
|
210
|
+
validatePaginatedRoute(route, path, errors, {
|
|
211
|
+
allowedKeys: ['path', 'page', 'totalPages', 'slug', 'posts', 'pagination', 'categories'],
|
|
212
|
+
requiredKeys: ['path', 'page', 'totalPages', 'slug', 'posts', 'pagination'],
|
|
213
|
+
routeCodePrefix: 'CATEGORY_ROUTE',
|
|
214
|
+
});
|
|
207
215
|
}
|
|
208
216
|
|
|
209
217
|
function validateTagRoute(route, path, errors) {
|
|
210
|
-
|
|
218
|
+
validatePaginatedRoute(route, path, errors, {
|
|
219
|
+
allowedKeys: ['path', 'page', 'totalPages', 'slug', 'posts', 'pagination', 'tags'],
|
|
220
|
+
requiredKeys: ['path', 'page', 'totalPages', 'slug', 'posts', 'pagination'],
|
|
221
|
+
routeCodePrefix: 'TAG_ROUTE',
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function validatePaginatedRoute(route, path, errors, options) {
|
|
226
|
+
validateClosedObject(route, path, errors, options.allowedKeys);
|
|
211
227
|
if (!isObject(route)) {
|
|
212
228
|
return;
|
|
213
229
|
}
|
|
214
230
|
|
|
215
|
-
validateNonEmptyString(route.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
}
|
|
231
|
+
validateNonEmptyString(route.path, `${path}.path`, `INVALID_${options.routeCodePrefix}_PATH`, errors);
|
|
232
|
+
validateInteger(route.page, `${path}.page`, `INVALID_${options.routeCodePrefix}_PAGE`, errors, { minimum: 1 });
|
|
233
|
+
validateInteger(route.totalPages, `${path}.totalPages`, `INVALID_${options.routeCodePrefix}_TOTAL_PAGES`, errors, { minimum: 1 });
|
|
234
|
+
validateString(route.posts, `${path}.posts`, `INVALID_${options.routeCodePrefix}_POSTS`, errors);
|
|
235
|
+
validateString(route.pagination, `${path}.pagination`, `INVALID_${options.routeCodePrefix}_PAGINATION`, errors);
|
|
222
236
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (!isObject(blocks)) {
|
|
226
|
-
return;
|
|
237
|
+
if ('slug' in route) {
|
|
238
|
+
validateNonEmptyString(route.slug, `${path}.slug`, `INVALID_${options.routeCodePrefix}_SLUG`, errors);
|
|
227
239
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
validateString(blocks[key], `${path}.${key}`, `INVALID_ROUTE_${key.toUpperCase()}`, errors);
|
|
240
|
+
if (route.categories !== undefined) {
|
|
241
|
+
validateString(route.categories, `${path}.categories`, `INVALID_${options.routeCodePrefix}_CATEGORIES`, errors);
|
|
231
242
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
243
|
+
if (route.tags !== undefined) {
|
|
244
|
+
validateString(route.tags, `${path}.tags`, `INVALID_${options.routeCodePrefix}_TAGS`, errors);
|
|
245
|
+
}
|
|
246
|
+
if (Number.isInteger(route.page) && Number.isInteger(route.totalPages) && route.page > route.totalPages) {
|
|
247
|
+
errors.push(issue(`INVALID_${options.routeCodePrefix}_PAGE`, `${path}.page`, 'Page cannot exceed totalPages'));
|
|
237
248
|
}
|
|
238
249
|
}
|
|
239
250
|
|
|
@@ -267,12 +278,10 @@ function validateClosedObject(value, path, errors, allowedKeys) {
|
|
|
267
278
|
|
|
268
279
|
function isOptionalKey(path, key) {
|
|
269
280
|
if (path === 'site') return key === 'logo' || key === 'social';
|
|
270
|
-
if (path.
|
|
271
|
-
if (path.
|
|
272
|
-
if (path.
|
|
273
|
-
if (path.
|
|
274
|
-
if (path.includes('.posts[')) return key === 'author_avatar' || key === 'featured_image';
|
|
275
|
-
if (path.includes('.categories[')) return key === 'description';
|
|
281
|
+
if (path.startsWith('content.posts[')) return key === 'author_avatar' || key === 'featured_image';
|
|
282
|
+
if (path.startsWith('content.categories[')) return key === 'description';
|
|
283
|
+
if (path.startsWith('routes.categories[')) return key === 'categories';
|
|
284
|
+
if (path.startsWith('routes.tags[')) return key === 'tags';
|
|
276
285
|
return false;
|
|
277
286
|
}
|
|
278
287
|
|
|
@@ -282,9 +291,9 @@ function validateObject(value, path, code, errors) {
|
|
|
282
291
|
}
|
|
283
292
|
}
|
|
284
293
|
|
|
285
|
-
function validateLiteral(value,
|
|
286
|
-
if (value !==
|
|
287
|
-
errors.push(issue(code, path, `Expected
|
|
294
|
+
function validateLiteral(value, literal, path, code, errors) {
|
|
295
|
+
if (value !== literal) {
|
|
296
|
+
errors.push(issue(code, path, `Expected literal value "${literal}"`));
|
|
288
297
|
}
|
|
289
298
|
}
|
|
290
299
|
|
|
@@ -305,8 +314,9 @@ function validateInteger(value, path, code, errors, options = {}) {
|
|
|
305
314
|
errors.push(issue(code, path, 'Expected an integer'));
|
|
306
315
|
return;
|
|
307
316
|
}
|
|
317
|
+
|
|
308
318
|
if (options.minimum !== undefined && value < options.minimum) {
|
|
309
|
-
errors.push(issue(code, path, `Expected
|
|
319
|
+
errors.push(issue(code, path, `Expected integer >= ${options.minimum}`));
|
|
310
320
|
}
|
|
311
321
|
}
|
|
312
322
|
|
|
@@ -316,35 +326,31 @@ function validateEnum(value, path, code, errors, allowedValues) {
|
|
|
316
326
|
}
|
|
317
327
|
}
|
|
318
328
|
|
|
319
|
-
function
|
|
329
|
+
function validateDateTimeString(value, path, code, errors) {
|
|
320
330
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
321
|
-
errors.push(issue(code, path, 'Expected a
|
|
331
|
+
errors.push(issue(code, path, 'Expected a date-time string'));
|
|
322
332
|
return;
|
|
323
333
|
}
|
|
324
334
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
errors.push(issue(code, path, 'Expected a valid URI'));
|
|
335
|
+
const date = new Date(value);
|
|
336
|
+
if (Number.isNaN(date.getTime())) {
|
|
337
|
+
errors.push(issue(code, path, 'Expected a valid date-time string'));
|
|
329
338
|
}
|
|
330
339
|
}
|
|
331
340
|
|
|
332
|
-
function
|
|
341
|
+
function validateUri(value, path, code, errors) {
|
|
333
342
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
334
|
-
errors.push(issue(code, path, 'Expected
|
|
343
|
+
errors.push(issue(code, path, 'Expected a URI string'));
|
|
335
344
|
return;
|
|
336
345
|
}
|
|
337
346
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
347
|
+
try {
|
|
348
|
+
new URL(value);
|
|
349
|
+
} catch {
|
|
350
|
+
errors.push(issue(code, path, 'Expected a valid URI'));
|
|
341
351
|
}
|
|
342
352
|
}
|
|
343
353
|
|
|
344
|
-
function isObject(value) {
|
|
345
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
354
|
function issue(code, path, message) {
|
|
349
355
|
return {
|
|
350
356
|
code,
|
|
@@ -353,3 +359,7 @@ function issue(code, path, message) {
|
|
|
353
359
|
severity: 'error',
|
|
354
360
|
};
|
|
355
361
|
}
|
|
362
|
+
|
|
363
|
+
function isObject(value) {
|
|
364
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
365
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://zeropress.dev/schemas/preview-data.v0.3.schema.json",
|
|
4
|
+
"title": "ZeroPress Theme Preview Data v0.3",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["version", "generator", "generated_at", "site", "content", "routes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"version": {
|
|
10
|
+
"const": "0.3"
|
|
11
|
+
},
|
|
12
|
+
"generator": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"minLength": 1
|
|
15
|
+
},
|
|
16
|
+
"generated_at": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"format": "date-time"
|
|
19
|
+
},
|
|
20
|
+
"site": {
|
|
21
|
+
"$ref": "#/$defs/site"
|
|
22
|
+
},
|
|
23
|
+
"content": {
|
|
24
|
+
"$ref": "#/$defs/content"
|
|
25
|
+
},
|
|
26
|
+
"routes": {
|
|
27
|
+
"$ref": "#/$defs/routes"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"$defs": {
|
|
31
|
+
"site": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": ["title", "description", "url", "language"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"title": { "type": "string", "minLength": 1 },
|
|
36
|
+
"description": { "type": "string" },
|
|
37
|
+
"url": { "type": "string", "format": "uri" },
|
|
38
|
+
"language": { "type": "string", "minLength": 2 },
|
|
39
|
+
"logo": { "type": "string", "format": "uri" },
|
|
40
|
+
"social": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"additionalProperties": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"additionalProperties": true
|
|
48
|
+
},
|
|
49
|
+
"previewPost": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": [
|
|
53
|
+
"id",
|
|
54
|
+
"public_id",
|
|
55
|
+
"title",
|
|
56
|
+
"slug",
|
|
57
|
+
"html",
|
|
58
|
+
"excerpt",
|
|
59
|
+
"published_at",
|
|
60
|
+
"updated_at",
|
|
61
|
+
"published_at_iso",
|
|
62
|
+
"updated_at_iso",
|
|
63
|
+
"reading_time",
|
|
64
|
+
"author_name",
|
|
65
|
+
"categories_html",
|
|
66
|
+
"tags_html",
|
|
67
|
+
"comments_html",
|
|
68
|
+
"status"
|
|
69
|
+
],
|
|
70
|
+
"properties": {
|
|
71
|
+
"id": { "type": "string", "minLength": 1 },
|
|
72
|
+
"public_id": { "type": "integer", "minimum": 1 },
|
|
73
|
+
"title": { "type": "string", "minLength": 1 },
|
|
74
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
75
|
+
"html": { "type": "string" },
|
|
76
|
+
"excerpt": { "type": "string" },
|
|
77
|
+
"published_at": { "type": "string" },
|
|
78
|
+
"updated_at": { "type": "string" },
|
|
79
|
+
"published_at_iso": { "type": "string", "format": "date-time" },
|
|
80
|
+
"updated_at_iso": { "type": "string", "format": "date-time" },
|
|
81
|
+
"reading_time": { "type": "string", "minLength": 1 },
|
|
82
|
+
"author_name": { "type": "string", "minLength": 1 },
|
|
83
|
+
"author_avatar": { "type": "string", "format": "uri" },
|
|
84
|
+
"featured_image": { "type": "string", "format": "uri" },
|
|
85
|
+
"categories_html": { "type": "string" },
|
|
86
|
+
"tags_html": { "type": "string" },
|
|
87
|
+
"comments_html": { "type": "string" },
|
|
88
|
+
"status": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"enum": ["published", "draft"]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"previewPage": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"additionalProperties": false,
|
|
97
|
+
"required": ["id", "title", "slug", "html", "status"],
|
|
98
|
+
"properties": {
|
|
99
|
+
"id": { "type": "string", "minLength": 1 },
|
|
100
|
+
"title": { "type": "string", "minLength": 1 },
|
|
101
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
102
|
+
"html": { "type": "string" },
|
|
103
|
+
"status": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"enum": ["published", "draft"]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"previewCategory": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"additionalProperties": false,
|
|
112
|
+
"required": ["id", "name", "slug", "postCount"],
|
|
113
|
+
"properties": {
|
|
114
|
+
"id": { "type": "string", "minLength": 1 },
|
|
115
|
+
"name": { "type": "string", "minLength": 1 },
|
|
116
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
117
|
+
"description": { "type": "string" },
|
|
118
|
+
"postCount": { "type": "integer", "minimum": 0 }
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"previewTag": {
|
|
122
|
+
"type": "object",
|
|
123
|
+
"additionalProperties": false,
|
|
124
|
+
"required": ["id", "name", "slug", "postCount"],
|
|
125
|
+
"properties": {
|
|
126
|
+
"id": { "type": "string", "minLength": 1 },
|
|
127
|
+
"name": { "type": "string", "minLength": 1 },
|
|
128
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
129
|
+
"postCount": { "type": "integer", "minimum": 0 }
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"content": {
|
|
133
|
+
"type": "object",
|
|
134
|
+
"additionalProperties": false,
|
|
135
|
+
"required": ["posts", "pages", "categories", "tags"],
|
|
136
|
+
"properties": {
|
|
137
|
+
"posts": {
|
|
138
|
+
"type": "array",
|
|
139
|
+
"items": { "$ref": "#/$defs/previewPost" }
|
|
140
|
+
},
|
|
141
|
+
"pages": {
|
|
142
|
+
"type": "array",
|
|
143
|
+
"items": { "$ref": "#/$defs/previewPage" }
|
|
144
|
+
},
|
|
145
|
+
"categories": {
|
|
146
|
+
"type": "array",
|
|
147
|
+
"items": { "$ref": "#/$defs/previewCategory" }
|
|
148
|
+
},
|
|
149
|
+
"tags": {
|
|
150
|
+
"type": "array",
|
|
151
|
+
"items": { "$ref": "#/$defs/previewTag" }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"paginatedRouteBase": {
|
|
156
|
+
"type": "object",
|
|
157
|
+
"additionalProperties": false,
|
|
158
|
+
"required": ["path", "page", "totalPages", "posts", "pagination"],
|
|
159
|
+
"properties": {
|
|
160
|
+
"path": { "type": "string", "minLength": 1 },
|
|
161
|
+
"page": { "type": "integer", "minimum": 1 },
|
|
162
|
+
"totalPages": { "type": "integer", "minimum": 1 },
|
|
163
|
+
"posts": { "type": "string" },
|
|
164
|
+
"pagination": { "type": "string" },
|
|
165
|
+
"categories": { "type": "string" },
|
|
166
|
+
"tags": { "type": "string" },
|
|
167
|
+
"slug": { "type": "string", "minLength": 1 }
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"indexRoute": {
|
|
171
|
+
"allOf": [
|
|
172
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
173
|
+
{ "required": ["path", "page", "totalPages", "posts", "pagination", "categories", "tags"] }
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"archiveRoute": {
|
|
177
|
+
"allOf": [
|
|
178
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
179
|
+
{ "required": ["path", "page", "totalPages", "posts", "pagination"] }
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"categoryRoute": {
|
|
183
|
+
"allOf": [
|
|
184
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
185
|
+
{ "required": ["path", "page", "totalPages", "slug", "posts", "pagination"] }
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
"tagRoute": {
|
|
189
|
+
"allOf": [
|
|
190
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
191
|
+
{ "required": ["path", "page", "totalPages", "slug", "posts", "pagination"] }
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
"routes": {
|
|
195
|
+
"type": "object",
|
|
196
|
+
"additionalProperties": false,
|
|
197
|
+
"required": ["index", "archive", "categories", "tags"],
|
|
198
|
+
"properties": {
|
|
199
|
+
"index": {
|
|
200
|
+
"type": "array",
|
|
201
|
+
"items": { "$ref": "#/$defs/indexRoute" }
|
|
202
|
+
},
|
|
203
|
+
"archive": {
|
|
204
|
+
"type": "array",
|
|
205
|
+
"items": { "$ref": "#/$defs/archiveRoute" }
|
|
206
|
+
},
|
|
207
|
+
"categories": {
|
|
208
|
+
"type": "array",
|
|
209
|
+
"items": { "$ref": "#/$defs/categoryRoute" }
|
|
210
|
+
},
|
|
211
|
+
"tags": {
|
|
212
|
+
"type": "array",
|
|
213
|
+
"items": { "$ref": "#/$defs/tagRoute" }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|