@zeropress/preview-data-validator 0.1.1 → 0.2.1
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 +2 -2
- package/package.json +3 -2
- package/src/index.d.ts +19 -18
- package/src/index.js +77 -59
- package/src/preview-data.v0.3.schema.json +224 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
Shared validation core for ZeroPress preview data v0.
|
|
7
|
+
Shared validation core for ZeroPress preview data v0.3.
|
|
8
8
|
|
|
9
9
|
This package is the canonical runtime contract for preview payloads consumed by:
|
|
10
10
|
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
Schema export:
|
|
32
32
|
|
|
33
33
|
```js
|
|
34
|
-
import schemaUrl from '@zeropress/preview-data-validator/preview-data.v0.
|
|
34
|
+
import schemaUrl from '@zeropress/preview-data-validator/preview-data.v0.3.schema.json';
|
|
35
35
|
```
|
|
36
36
|
|
|
37
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.1",
|
|
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
|
|
|
@@ -43,7 +43,7 @@ function validateSite(site, path, errors) {
|
|
|
43
43
|
|
|
44
44
|
validateNonEmptyString(site.title, `${path}.title`, 'INVALID_SITE_TITLE', errors);
|
|
45
45
|
validateString(site.description, `${path}.description`, 'INVALID_SITE_DESCRIPTION', errors);
|
|
46
|
-
|
|
46
|
+
validateSiteUri(site.url, `${path}.url`, 'INVALID_SITE_URL', errors);
|
|
47
47
|
validateNonEmptyString(site.language, `${path}.language`, 'INVALID_SITE_LANGUAGE', errors);
|
|
48
48
|
|
|
49
49
|
if (site.logo !== undefined) {
|
|
@@ -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.endsWith('.index')) return false;
|
|
271
|
-
if (path.endsWith('.archive')) return key === 'categories' || key === 'tags';
|
|
272
|
-
if (path.startsWith('routes.categories[')) return key === 'categories';
|
|
273
|
-
if (path.startsWith('routes.tags[')) return key === 'tags';
|
|
274
281
|
if (path.startsWith('content.posts[')) return key === 'author_avatar' || key === 'featured_image';
|
|
275
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,6 +326,18 @@ function validateEnum(value, path, code, errors, allowedValues) {
|
|
|
316
326
|
}
|
|
317
327
|
}
|
|
318
328
|
|
|
329
|
+
function validateDateTimeString(value, path, code, errors) {
|
|
330
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
331
|
+
errors.push(issue(code, path, 'Expected a date-time string'));
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const date = new Date(value);
|
|
336
|
+
if (Number.isNaN(date.getTime())) {
|
|
337
|
+
errors.push(issue(code, path, 'Expected a valid date-time string'));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
319
341
|
function validateUri(value, path, code, errors) {
|
|
320
342
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
321
343
|
errors.push(issue(code, path, 'Expected a URI string'));
|
|
@@ -329,20 +351,12 @@ function validateUri(value, path, code, errors) {
|
|
|
329
351
|
}
|
|
330
352
|
}
|
|
331
353
|
|
|
332
|
-
function
|
|
333
|
-
if (
|
|
334
|
-
errors.push(issue(code, path, 'Expected an ISO date-time string'));
|
|
354
|
+
function validateSiteUri(value, path, code, errors) {
|
|
355
|
+
if (value === '') {
|
|
335
356
|
return;
|
|
336
357
|
}
|
|
337
358
|
|
|
338
|
-
|
|
339
|
-
if (Number.isNaN(parsed)) {
|
|
340
|
-
errors.push(issue(code, path, 'Expected a valid ISO date-time string'));
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function isObject(value) {
|
|
345
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
359
|
+
validateUri(value, path, code, errors);
|
|
346
360
|
}
|
|
347
361
|
|
|
348
362
|
function issue(code, path, message) {
|
|
@@ -353,3 +367,7 @@ function issue(code, path, message) {
|
|
|
353
367
|
severity: 'error',
|
|
354
368
|
};
|
|
355
369
|
}
|
|
370
|
+
|
|
371
|
+
function isObject(value) {
|
|
372
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
373
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
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": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"anyOf": [
|
|
40
|
+
{ "const": "" },
|
|
41
|
+
{ "format": "uri" }
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"language": { "type": "string", "minLength": 2 },
|
|
45
|
+
"logo": { "type": "string", "format": "uri" },
|
|
46
|
+
"social": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"additionalProperties": {
|
|
49
|
+
"type": "string"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"additionalProperties": true
|
|
54
|
+
},
|
|
55
|
+
"previewPost": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": [
|
|
59
|
+
"id",
|
|
60
|
+
"public_id",
|
|
61
|
+
"title",
|
|
62
|
+
"slug",
|
|
63
|
+
"html",
|
|
64
|
+
"excerpt",
|
|
65
|
+
"published_at",
|
|
66
|
+
"updated_at",
|
|
67
|
+
"published_at_iso",
|
|
68
|
+
"updated_at_iso",
|
|
69
|
+
"reading_time",
|
|
70
|
+
"author_name",
|
|
71
|
+
"categories_html",
|
|
72
|
+
"tags_html",
|
|
73
|
+
"comments_html",
|
|
74
|
+
"status"
|
|
75
|
+
],
|
|
76
|
+
"properties": {
|
|
77
|
+
"id": { "type": "string", "minLength": 1 },
|
|
78
|
+
"public_id": { "type": "integer", "minimum": 1 },
|
|
79
|
+
"title": { "type": "string", "minLength": 1 },
|
|
80
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
81
|
+
"html": { "type": "string" },
|
|
82
|
+
"excerpt": { "type": "string" },
|
|
83
|
+
"published_at": { "type": "string" },
|
|
84
|
+
"updated_at": { "type": "string" },
|
|
85
|
+
"published_at_iso": { "type": "string", "format": "date-time" },
|
|
86
|
+
"updated_at_iso": { "type": "string", "format": "date-time" },
|
|
87
|
+
"reading_time": { "type": "string", "minLength": 1 },
|
|
88
|
+
"author_name": { "type": "string", "minLength": 1 },
|
|
89
|
+
"author_avatar": { "type": "string", "format": "uri" },
|
|
90
|
+
"featured_image": { "type": "string", "format": "uri" },
|
|
91
|
+
"categories_html": { "type": "string" },
|
|
92
|
+
"tags_html": { "type": "string" },
|
|
93
|
+
"comments_html": { "type": "string" },
|
|
94
|
+
"status": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"enum": ["published", "draft"]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"previewPage": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"additionalProperties": false,
|
|
103
|
+
"required": ["id", "title", "slug", "html", "status"],
|
|
104
|
+
"properties": {
|
|
105
|
+
"id": { "type": "string", "minLength": 1 },
|
|
106
|
+
"title": { "type": "string", "minLength": 1 },
|
|
107
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
108
|
+
"html": { "type": "string" },
|
|
109
|
+
"status": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"enum": ["published", "draft"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"previewCategory": {
|
|
116
|
+
"type": "object",
|
|
117
|
+
"additionalProperties": false,
|
|
118
|
+
"required": ["id", "name", "slug", "postCount"],
|
|
119
|
+
"properties": {
|
|
120
|
+
"id": { "type": "string", "minLength": 1 },
|
|
121
|
+
"name": { "type": "string", "minLength": 1 },
|
|
122
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
123
|
+
"description": { "type": "string" },
|
|
124
|
+
"postCount": { "type": "integer", "minimum": 0 }
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"previewTag": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"additionalProperties": false,
|
|
130
|
+
"required": ["id", "name", "slug", "postCount"],
|
|
131
|
+
"properties": {
|
|
132
|
+
"id": { "type": "string", "minLength": 1 },
|
|
133
|
+
"name": { "type": "string", "minLength": 1 },
|
|
134
|
+
"slug": { "type": "string", "minLength": 1 },
|
|
135
|
+
"postCount": { "type": "integer", "minimum": 0 }
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"content": {
|
|
139
|
+
"type": "object",
|
|
140
|
+
"additionalProperties": false,
|
|
141
|
+
"required": ["posts", "pages", "categories", "tags"],
|
|
142
|
+
"properties": {
|
|
143
|
+
"posts": {
|
|
144
|
+
"type": "array",
|
|
145
|
+
"items": { "$ref": "#/$defs/previewPost" }
|
|
146
|
+
},
|
|
147
|
+
"pages": {
|
|
148
|
+
"type": "array",
|
|
149
|
+
"items": { "$ref": "#/$defs/previewPage" }
|
|
150
|
+
},
|
|
151
|
+
"categories": {
|
|
152
|
+
"type": "array",
|
|
153
|
+
"items": { "$ref": "#/$defs/previewCategory" }
|
|
154
|
+
},
|
|
155
|
+
"tags": {
|
|
156
|
+
"type": "array",
|
|
157
|
+
"items": { "$ref": "#/$defs/previewTag" }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"paginatedRouteBase": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"additionalProperties": false,
|
|
164
|
+
"required": ["path", "page", "totalPages", "posts", "pagination"],
|
|
165
|
+
"properties": {
|
|
166
|
+
"path": { "type": "string", "minLength": 1 },
|
|
167
|
+
"page": { "type": "integer", "minimum": 1 },
|
|
168
|
+
"totalPages": { "type": "integer", "minimum": 1 },
|
|
169
|
+
"posts": { "type": "string" },
|
|
170
|
+
"pagination": { "type": "string" },
|
|
171
|
+
"categories": { "type": "string" },
|
|
172
|
+
"tags": { "type": "string" },
|
|
173
|
+
"slug": { "type": "string", "minLength": 1 }
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"indexRoute": {
|
|
177
|
+
"allOf": [
|
|
178
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
179
|
+
{ "required": ["path", "page", "totalPages", "posts", "pagination", "categories", "tags"] }
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"archiveRoute": {
|
|
183
|
+
"allOf": [
|
|
184
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
185
|
+
{ "required": ["path", "page", "totalPages", "posts", "pagination"] }
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
"categoryRoute": {
|
|
189
|
+
"allOf": [
|
|
190
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
191
|
+
{ "required": ["path", "page", "totalPages", "slug", "posts", "pagination"] }
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
"tagRoute": {
|
|
195
|
+
"allOf": [
|
|
196
|
+
{ "$ref": "#/$defs/paginatedRouteBase" },
|
|
197
|
+
{ "required": ["path", "page", "totalPages", "slug", "posts", "pagination"] }
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"routes": {
|
|
201
|
+
"type": "object",
|
|
202
|
+
"additionalProperties": false,
|
|
203
|
+
"required": ["index", "archive", "categories", "tags"],
|
|
204
|
+
"properties": {
|
|
205
|
+
"index": {
|
|
206
|
+
"type": "array",
|
|
207
|
+
"items": { "$ref": "#/$defs/indexRoute" }
|
|
208
|
+
},
|
|
209
|
+
"archive": {
|
|
210
|
+
"type": "array",
|
|
211
|
+
"items": { "$ref": "#/$defs/archiveRoute" }
|
|
212
|
+
},
|
|
213
|
+
"categories": {
|
|
214
|
+
"type": "array",
|
|
215
|
+
"items": { "$ref": "#/$defs/categoryRoute" }
|
|
216
|
+
},
|
|
217
|
+
"tags": {
|
|
218
|
+
"type": "array",
|
|
219
|
+
"items": { "$ref": "#/$defs/tagRoute" }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|