@storyblok/schema 0.1.0-alpha.0 → 0.1.0-alpha.2
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/dist/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/field-plugins/index.cjs +4 -0
- package/dist/field-plugins/index.d.cts +2 -0
- package/dist/field-plugins/index.d.mts +2 -0
- package/dist/field-plugins/index.mjs +3 -0
- package/dist/field-plugins/storyblok-color-field.cjs +32 -0
- package/dist/field-plugins/storyblok-color-field.cjs.map +1 -0
- package/dist/field-plugins/storyblok-color-field.d.cts +16 -0
- package/dist/field-plugins/storyblok-color-field.d.mts +16 -0
- package/dist/field-plugins/storyblok-color-field.mjs +32 -0
- package/dist/field-plugins/storyblok-color-field.mjs.map +1 -0
- package/dist/generated/capi/types.gen.d.cts +1 -126
- package/dist/generated/capi/types.gen.d.mts +1 -126
- package/dist/generated/mapi/_internal.gen.d.cts +1 -171
- package/dist/generated/mapi/_internal.gen.d.mts +1 -171
- package/dist/generated/overlay/zod.gen.cjs +407 -0
- package/dist/generated/overlay/zod.gen.cjs.map +1 -0
- package/dist/generated/overlay/zod.gen.mjs +402 -0
- package/dist/generated/overlay/zod.gen.mjs.map +1 -0
- package/dist/generated/types/block.d.cts +27 -14
- package/dist/generated/types/block.d.mts +27 -14
- package/dist/generated/types/field.d.cts +48 -17
- package/dist/generated/types/field.d.mts +48 -17
- package/dist/generated/types/mapi-story.d.cts +6 -10
- package/dist/generated/types/mapi-story.d.mts +6 -10
- package/dist/generated/types/story.d.cts +3 -3
- package/dist/generated/types/story.d.mts +3 -3
- package/dist/helpers/define-block.cjs +10 -28
- package/dist/helpers/define-block.cjs.map +1 -1
- package/dist/helpers/define-block.d.cts +14 -31
- package/dist/helpers/define-block.d.mts +14 -31
- package/dist/helpers/define-block.mjs +11 -27
- package/dist/helpers/define-block.mjs.map +1 -1
- package/dist/helpers/define-datasource.cjs +0 -16
- package/dist/helpers/define-datasource.cjs.map +1 -1
- package/dist/helpers/define-datasource.d.cts +14 -23
- package/dist/helpers/define-datasource.d.mts +14 -23
- package/dist/helpers/define-datasource.mjs +1 -15
- package/dist/helpers/define-datasource.mjs.map +1 -1
- package/dist/helpers/define-field-plugin.cjs +21 -0
- package/dist/helpers/define-field-plugin.cjs.map +1 -0
- package/dist/helpers/define-field-plugin.d.cts +33 -0
- package/dist/helpers/define-field-plugin.d.mts +33 -0
- package/dist/helpers/define-field-plugin.mjs +20 -0
- package/dist/helpers/define-field-plugin.mjs.map +1 -0
- package/dist/helpers/define-field.cjs +11 -11
- package/dist/helpers/define-field.cjs.map +1 -1
- package/dist/helpers/define-field.d.cts +46 -85
- package/dist/helpers/define-field.d.mts +46 -85
- package/dist/helpers/define-field.mjs +12 -11
- package/dist/helpers/define-field.mjs.map +1 -1
- package/dist/helpers/define-schema.cjs +22 -0
- package/dist/helpers/define-schema.cjs.map +1 -0
- package/dist/helpers/define-schema.d.cts +28 -0
- package/dist/helpers/define-schema.d.mts +28 -0
- package/dist/helpers/define-schema.mjs +21 -0
- package/dist/helpers/define-schema.mjs.map +1 -0
- package/dist/helpers/schema-type.d.cts +21 -17
- package/dist/helpers/schema-type.d.mts +21 -17
- package/dist/index.cjs +10 -47
- package/dist/index.d.cts +13 -20
- package/dist/index.d.mts +13 -20
- package/dist/index.mjs +8 -15
- package/dist/utils/is-record.cjs +10 -0
- package/dist/utils/is-record.cjs.map +1 -0
- package/dist/utils/is-record.mjs +9 -0
- package/dist/utils/is-record.mjs.map +1 -0
- package/dist/validators/create-story-validator.cjs +37 -0
- package/dist/validators/create-story-validator.cjs.map +1 -0
- package/dist/validators/create-story-validator.d.cts +18 -0
- package/dist/validators/create-story-validator.d.mts +18 -0
- package/dist/validators/create-story-validator.mjs +37 -0
- package/dist/validators/create-story-validator.mjs.map +1 -0
- package/dist/validators/internal-schemas.cjs +1 -0
- package/dist/validators/internal-schemas.mjs +3 -0
- package/dist/validators/shapes.cjs +12 -0
- package/dist/validators/shapes.cjs.map +1 -0
- package/dist/validators/shapes.d.cts +71 -0
- package/dist/validators/shapes.d.mts +71 -0
- package/dist/validators/shapes.mjs +12 -0
- package/dist/validators/shapes.mjs.map +1 -0
- package/dist/validators/types.d.cts +25 -0
- package/dist/validators/types.d.mts +25 -0
- package/dist/validators/validate-schema.cjs +145 -0
- package/dist/validators/validate-schema.cjs.map +1 -0
- package/dist/validators/validate-schema.d.cts +19 -0
- package/dist/validators/validate-schema.d.mts +19 -0
- package/dist/validators/validate-schema.mjs +145 -0
- package/dist/validators/validate-schema.mjs.map +1 -0
- package/dist/validators/validate-story.cjs +285 -0
- package/dist/validators/validate-story.cjs.map +1 -0
- package/dist/validators/validate-story.d.cts +17 -0
- package/dist/validators/validate-story.d.mts +17 -0
- package/dist/validators/validate-story.mjs +284 -0
- package/dist/validators/validate-story.mjs.map +1 -0
- package/package.json +17 -2
- package/dist/generated/mapi/types.gen.d.cts +0 -1272
- package/dist/generated/mapi/types.gen.d.mts +0 -1272
- package/dist/helpers/create-story-helpers.cjs +0 -42
- package/dist/helpers/create-story-helpers.cjs.map +0 -1
- package/dist/helpers/create-story-helpers.d.cts +0 -50
- package/dist/helpers/create-story-helpers.d.mts +0 -50
- package/dist/helpers/create-story-helpers.mjs +0 -42
- package/dist/helpers/create-story-helpers.mjs.map +0 -1
- package/dist/helpers/define-asset-folder.cjs +0 -46
- package/dist/helpers/define-asset-folder.cjs.map +0 -1
- package/dist/helpers/define-asset-folder.d.cts +0 -33
- package/dist/helpers/define-asset-folder.d.mts +0 -33
- package/dist/helpers/define-asset-folder.mjs +0 -43
- package/dist/helpers/define-asset-folder.mjs.map +0 -1
- package/dist/helpers/define-asset.cjs +0 -60
- package/dist/helpers/define-asset.cjs.map +0 -1
- package/dist/helpers/define-asset.d.cts +0 -32
- package/dist/helpers/define-asset.d.mts +0 -32
- package/dist/helpers/define-asset.mjs +0 -57
- package/dist/helpers/define-asset.mjs.map +0 -1
- package/dist/helpers/define-block-folder.cjs +0 -44
- package/dist/helpers/define-block-folder.cjs.map +0 -1
- package/dist/helpers/define-block-folder.d.cts +0 -34
- package/dist/helpers/define-block-folder.d.mts +0 -34
- package/dist/helpers/define-block-folder.mjs +0 -41
- package/dist/helpers/define-block-folder.mjs.map +0 -1
- package/dist/helpers/define-datasource-entry.cjs +0 -47
- package/dist/helpers/define-datasource-entry.cjs.map +0 -1
- package/dist/helpers/define-datasource-entry.d.cts +0 -49
- package/dist/helpers/define-datasource-entry.d.mts +0 -49
- package/dist/helpers/define-datasource-entry.mjs +0 -43
- package/dist/helpers/define-datasource-entry.mjs.map +0 -1
- package/dist/helpers/define-internal-tag.cjs +0 -41
- package/dist/helpers/define-internal-tag.cjs.map +0 -1
- package/dist/helpers/define-internal-tag.d.cts +0 -34
- package/dist/helpers/define-internal-tag.d.mts +0 -34
- package/dist/helpers/define-internal-tag.mjs +0 -38
- package/dist/helpers/define-internal-tag.mjs.map +0 -1
- package/dist/helpers/define-link.cjs +0 -23
- package/dist/helpers/define-link.cjs.map +0 -1
- package/dist/helpers/define-link.d.cts +0 -32
- package/dist/helpers/define-link.d.mts +0 -32
- package/dist/helpers/define-link.mjs +0 -22
- package/dist/helpers/define-link.mjs.map +0 -1
- package/dist/helpers/define-preset.cjs +0 -44
- package/dist/helpers/define-preset.cjs.map +0 -1
- package/dist/helpers/define-preset.d.cts +0 -35
- package/dist/helpers/define-preset.d.mts +0 -35
- package/dist/helpers/define-preset.mjs +0 -41
- package/dist/helpers/define-preset.mjs.map +0 -1
- package/dist/helpers/define-space.cjs +0 -47
- package/dist/helpers/define-space.cjs.map +0 -1
- package/dist/helpers/define-space.d.cts +0 -31
- package/dist/helpers/define-space.d.mts +0 -31
- package/dist/helpers/define-space.mjs +0 -44
- package/dist/helpers/define-space.mjs.map +0 -1
- package/dist/helpers/define-story.cjs +0 -122
- package/dist/helpers/define-story.cjs.map +0 -1
- package/dist/helpers/define-story.d.cts +0 -135
- package/dist/helpers/define-story.d.mts +0 -135
- package/dist/helpers/define-story.mjs +0 -118
- package/dist/helpers/define-story.mjs.map +0 -1
- package/dist/helpers/define-tag.cjs +0 -13
- package/dist/helpers/define-tag.cjs.map +0 -1
- package/dist/helpers/define-tag.d.cts +0 -23
- package/dist/helpers/define-tag.d.mts +0 -23
- package/dist/helpers/define-tag.mjs +0 -12
- package/dist/helpers/define-tag.mjs.map +0 -1
- package/dist/helpers/define-user.cjs +0 -50
- package/dist/helpers/define-user.cjs.map +0 -1
- package/dist/helpers/define-user.d.cts +0 -26
- package/dist/helpers/define-user.d.mts +0 -26
- package/dist/helpers/define-user.mjs +0 -48
- package/dist/helpers/define-user.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { defineAssetCreate, defineAssetUpdate, defineMapiAsset } from "./helpers/define-asset.mjs";
|
|
4
|
-
import { defineAssetFolder, defineAssetFolderCreate, defineAssetFolderUpdate } from "./helpers/define-asset-folder.mjs";
|
|
5
|
-
import { defineBlock, defineBlockCreate, defineBlockUpdate } from "./helpers/define-block.mjs";
|
|
6
|
-
import { defineBlockFolder, defineBlockFolderCreate, defineBlockFolderUpdate } from "./helpers/define-block-folder.mjs";
|
|
7
|
-
import { defineDatasource, defineDatasourceCreate, defineDatasourceUpdate } from "./helpers/define-datasource.mjs";
|
|
8
|
-
import { defineDatasourceEntry, defineDatasourceEntryCreate, defineDatasourceEntryUpdate, defineMapiDatasourceEntry } from "./helpers/define-datasource-entry.mjs";
|
|
1
|
+
import { defineBlock } from "./helpers/define-block.mjs";
|
|
2
|
+
import { defineDatasource } from "./helpers/define-datasource.mjs";
|
|
9
3
|
import { defineField } from "./helpers/define-field.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { defineUser, defineUserUpdate } from "./helpers/define-user.mjs";
|
|
4
|
+
import { defineFieldPlugin } from "./helpers/define-field-plugin.mjs";
|
|
5
|
+
import { defineSchema } from "./helpers/define-schema.mjs";
|
|
6
|
+
import { validateStory } from "./validators/validate-story.mjs";
|
|
7
|
+
import { createStoryValidator } from "./validators/create-story-validator.mjs";
|
|
8
|
+
import { validateSchema } from "./validators/validate-schema.mjs";
|
|
16
9
|
|
|
17
|
-
export {
|
|
10
|
+
export { createStoryValidator, defineBlock, defineDatasource, defineField, defineFieldPlugin, defineSchema, validateSchema, validateStory };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/is-record.ts
|
|
3
|
+
/** Type guard for a plain object (record). */
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
exports.isRecord = isRecord;
|
|
10
|
+
//# sourceMappingURL=is-record.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-record.cjs","names":[],"sources":["../../src/utils/is-record.ts"],"sourcesContent":["/** Type guard for a plain object (record). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"mappings":";;;AACA,SAAgB,SAAS,OAAkD;AACzE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/utils/is-record.ts
|
|
2
|
+
/** Type guard for a plain object (record). */
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
//#endregion
|
|
8
|
+
export { isRecord };
|
|
9
|
+
//# sourceMappingURL=is-record.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-record.mjs","names":[],"sources":["../../src/utils/is-record.ts"],"sourcesContent":["/** Type guard for a plain object (record). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"mappings":";;AACA,SAAgB,SAAS,OAAkD;AACzE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const require_is_record = require('../utils/is-record.cjs');
|
|
2
|
+
const require_validate_story = require('./validate-story.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/validators/create-story-validator.ts
|
|
5
|
+
/**
|
|
6
|
+
* Wraps {@link validateStory} as a [Standard Schema](https://standardschema.dev)
|
|
7
|
+
* validator, so a story for `rootBlock` composes with any Standard Schema
|
|
8
|
+
* tooling (e.g. as a tRPC input or a form resolver). The root content
|
|
9
|
+
* `component` is asserted to match `rootBlock.name`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const validator = createStoryValidator(page, schema);
|
|
13
|
+
* const result = validator['~standard'].validate(story);
|
|
14
|
+
*/
|
|
15
|
+
function createStoryValidator(rootBlock, schema) {
|
|
16
|
+
return { "~standard": {
|
|
17
|
+
version: 1,
|
|
18
|
+
vendor: "storyblok-schema",
|
|
19
|
+
validate(value) {
|
|
20
|
+
const issues = require_validate_story.validateStory(value, schema).issues.filter((issue) => issue.severity === "error").map((issue) => ({
|
|
21
|
+
message: issue.message,
|
|
22
|
+
path: issue.path
|
|
23
|
+
}));
|
|
24
|
+
const content = require_is_record.isRecord(value) ? value.content : void 0;
|
|
25
|
+
const component = require_is_record.isRecord(content) ? content.component : void 0;
|
|
26
|
+
if (component !== void 0 && component !== rootBlock.name) issues.push({
|
|
27
|
+
message: `Expected root component "${rootBlock.name}", received "${String(component)}".`,
|
|
28
|
+
path: ["content", "component"]
|
|
29
|
+
});
|
|
30
|
+
return issues.length > 0 ? { issues } : { value };
|
|
31
|
+
}
|
|
32
|
+
} };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.createStoryValidator = createStoryValidator;
|
|
37
|
+
//# sourceMappingURL=create-story-validator.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-story-validator.cjs","names":["validateStory","isRecord"],"sources":["../../src/validators/create-story-validator.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { SchemaBlockLike, SchemaLike } from './shapes';\nimport { isRecord } from './shapes';\nimport { validateStory } from './validate-story';\n\n/**\n * Wraps {@link validateStory} as a [Standard Schema](https://standardschema.dev)\n * validator, so a story for `rootBlock` composes with any Standard Schema\n * tooling (e.g. as a tRPC input or a form resolver). The root content\n * `component` is asserted to match `rootBlock.name`.\n *\n * @example\n * const validator = createStoryValidator(page, schema);\n * const result = validator['~standard'].validate(story);\n */\nexport function createStoryValidator(\n rootBlock: SchemaBlockLike,\n schema: SchemaLike,\n): StandardSchemaV1<unknown, unknown> {\n return {\n '~standard': {\n version: 1,\n vendor: 'storyblok-schema',\n validate(value) {\n const result = validateStory(value, schema);\n const issues = result.issues\n .filter(issue => issue.severity === 'error')\n .map(issue => ({ message: issue.message, path: issue.path }));\n\n const content = isRecord(value) ? value.content : undefined;\n const component = isRecord(content) ? content.component : undefined;\n if (component !== undefined && component !== rootBlock.name) {\n issues.push({\n message: `Expected root component \"${rootBlock.name}\", received \"${String(component)}\".`,\n path: ['content', 'component'],\n });\n }\n\n return issues.length > 0 ? { issues } : { value };\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,qBACd,WACA,QACoC;AACpC,QAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,SAAS,OAAO;GAEd,MAAM,SADSA,qCAAc,OAAO,OAAO,CACrB,OACnB,QAAO,UAAS,MAAM,aAAa,QAAQ,CAC3C,KAAI,WAAU;IAAE,SAAS,MAAM;IAAS,MAAM,MAAM;IAAM,EAAE;GAE/D,MAAM,UAAUC,2BAAS,MAAM,GAAG,MAAM,UAAU;GAClD,MAAM,YAAYA,2BAAS,QAAQ,GAAG,QAAQ,YAAY;AAC1D,OAAI,cAAc,UAAa,cAAc,UAAU,KACrD,QAAO,KAAK;IACV,SAAS,4BAA4B,UAAU,KAAK,eAAe,OAAO,UAAU,CAAC;IACrF,MAAM,CAAC,WAAW,YAAY;IAC/B,CAAC;AAGJ,UAAO,OAAO,SAAS,IAAI,EAAE,QAAQ,GAAG,EAAE,OAAO;;EAEpD,EACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SchemaBlockLike, SchemaLike } from "./shapes.cjs";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/validators/create-story-validator.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Wraps {@link validateStory} as a [Standard Schema](https://standardschema.dev)
|
|
7
|
+
* validator, so a story for `rootBlock` composes with any Standard Schema
|
|
8
|
+
* tooling (e.g. as a tRPC input or a form resolver). The root content
|
|
9
|
+
* `component` is asserted to match `rootBlock.name`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const validator = createStoryValidator(page, schema);
|
|
13
|
+
* const result = validator['~standard'].validate(story);
|
|
14
|
+
*/
|
|
15
|
+
declare function createStoryValidator(rootBlock: SchemaBlockLike, schema: SchemaLike): StandardSchemaV1<unknown, unknown>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { createStoryValidator };
|
|
18
|
+
//# sourceMappingURL=create-story-validator.d.cts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SchemaBlockLike, SchemaLike } from "./shapes.mjs";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/validators/create-story-validator.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Wraps {@link validateStory} as a [Standard Schema](https://standardschema.dev)
|
|
7
|
+
* validator, so a story for `rootBlock` composes with any Standard Schema
|
|
8
|
+
* tooling (e.g. as a tRPC input or a form resolver). The root content
|
|
9
|
+
* `component` is asserted to match `rootBlock.name`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const validator = createStoryValidator(page, schema);
|
|
13
|
+
* const result = validator['~standard'].validate(story);
|
|
14
|
+
*/
|
|
15
|
+
declare function createStoryValidator(rootBlock: SchemaBlockLike, schema: SchemaLike): StandardSchemaV1<unknown, unknown>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { createStoryValidator };
|
|
18
|
+
//# sourceMappingURL=create-story-validator.d.mts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { isRecord } from "../utils/is-record.mjs";
|
|
2
|
+
import { validateStory } from "./validate-story.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/validators/create-story-validator.ts
|
|
5
|
+
/**
|
|
6
|
+
* Wraps {@link validateStory} as a [Standard Schema](https://standardschema.dev)
|
|
7
|
+
* validator, so a story for `rootBlock` composes with any Standard Schema
|
|
8
|
+
* tooling (e.g. as a tRPC input or a form resolver). The root content
|
|
9
|
+
* `component` is asserted to match `rootBlock.name`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const validator = createStoryValidator(page, schema);
|
|
13
|
+
* const result = validator['~standard'].validate(story);
|
|
14
|
+
*/
|
|
15
|
+
function createStoryValidator(rootBlock, schema) {
|
|
16
|
+
return { "~standard": {
|
|
17
|
+
version: 1,
|
|
18
|
+
vendor: "storyblok-schema",
|
|
19
|
+
validate(value) {
|
|
20
|
+
const issues = validateStory(value, schema).issues.filter((issue) => issue.severity === "error").map((issue) => ({
|
|
21
|
+
message: issue.message,
|
|
22
|
+
path: issue.path
|
|
23
|
+
}));
|
|
24
|
+
const content = isRecord(value) ? value.content : void 0;
|
|
25
|
+
const component = isRecord(content) ? content.component : void 0;
|
|
26
|
+
if (component !== void 0 && component !== rootBlock.name) issues.push({
|
|
27
|
+
message: `Expected root component "${rootBlock.name}", received "${String(component)}".`,
|
|
28
|
+
path: ["content", "component"]
|
|
29
|
+
});
|
|
30
|
+
return issues.length > 0 ? { issues } : { value };
|
|
31
|
+
}
|
|
32
|
+
} };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createStoryValidator };
|
|
37
|
+
//# sourceMappingURL=create-story-validator.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-story-validator.mjs","names":[],"sources":["../../src/validators/create-story-validator.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { SchemaBlockLike, SchemaLike } from './shapes';\nimport { isRecord } from './shapes';\nimport { validateStory } from './validate-story';\n\n/**\n * Wraps {@link validateStory} as a [Standard Schema](https://standardschema.dev)\n * validator, so a story for `rootBlock` composes with any Standard Schema\n * tooling (e.g. as a tRPC input or a form resolver). The root content\n * `component` is asserted to match `rootBlock.name`.\n *\n * @example\n * const validator = createStoryValidator(page, schema);\n * const result = validator['~standard'].validate(story);\n */\nexport function createStoryValidator(\n rootBlock: SchemaBlockLike,\n schema: SchemaLike,\n): StandardSchemaV1<unknown, unknown> {\n return {\n '~standard': {\n version: 1,\n vendor: 'storyblok-schema',\n validate(value) {\n const result = validateStory(value, schema);\n const issues = result.issues\n .filter(issue => issue.severity === 'error')\n .map(issue => ({ message: issue.message, path: issue.path }));\n\n const content = isRecord(value) ? value.content : undefined;\n const component = isRecord(content) ? content.component : undefined;\n if (component !== undefined && component !== rootBlock.name) {\n issues.push({\n message: `Expected root component \"${rootBlock.name}\", received \"${String(component)}\".`,\n path: ['content', 'component'],\n });\n }\n\n return issues.length > 0 ? { issues } : { value };\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,qBACd,WACA,QACoC;AACpC,QAAO,EACL,aAAa;EACX,SAAS;EACT,QAAQ;EACR,SAAS,OAAO;GAEd,MAAM,SADS,cAAc,OAAO,OAAO,CACrB,OACnB,QAAO,UAAS,MAAM,aAAa,QAAQ,CAC3C,KAAI,WAAU;IAAE,SAAS,MAAM;IAAS,MAAM,MAAM;IAAM,EAAE;GAE/D,MAAM,UAAU,SAAS,MAAM,GAAG,MAAM,UAAU;GAClD,MAAM,YAAY,SAAS,QAAQ,GAAG,QAAQ,YAAY;AAC1D,OAAI,cAAc,UAAa,cAAc,UAAU,KACrD,QAAO,KAAK;IACV,SAAS,4BAA4B,UAAU,KAAK,eAAe,OAAO,UAAU,CAAC;IACrF,MAAM,CAAC,WAAW,YAAY;IAC/B,CAAC;AAGJ,UAAO,OAAO,SAAS,IAAI,EAAE,QAAQ,GAAG,EAAE,OAAO;;EAEpD,EACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const require_zod_gen = require('../generated/overlay/zod.gen.cjs');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const require_is_record = require('../utils/is-record.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/validators/shapes.ts
|
|
4
|
+
/** Normalizes a record-or-array of entities to an array of values. */
|
|
5
|
+
function toValues(input) {
|
|
6
|
+
if (!input) return [];
|
|
7
|
+
return Array.isArray(input) ? [...input] : Object.values(input);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
exports.toValues = toValues;
|
|
12
|
+
//# sourceMappingURL=shapes.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.cjs","names":[],"sources":["../../src/validators/shapes.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { FieldType } from '../generated/types/field';\n\nexport { isRecord } from '../utils/is-record';\n\n/**\n * Loose structural views of the content-shape definitions, used internally by\n * the validators. A real `Block` / `Datasource` (from the `define*` helpers) is\n * structurally assignable to these, but they also tolerate the plain objects a\n * validator may receive at runtime.\n */\n\n/** A single field within a block's `fields` array. */\nexport interface SchemaFieldLike {\n name: string;\n type: FieldType;\n /** `custom`: the field plugin discriminant, matched against registered `fieldPlugins`. */\n field_type?: string;\n required?: boolean;\n /** Normalized block-name references for `bloks` fields. */\n allow?: readonly string[];\n /** Normalized datasource slug for option/options fields. */\n datasource?: string;\n // Value constraints enforced by `validateStory` (all optional).\n /** `text`/`textarea`/`markdown`: maximum string length. */\n max_length?: number;\n /** `text`/`textarea`: legacy alias for `max_length`. */\n maxlength?: number;\n /** `text`/`textarea`: minimum string length. */\n minlength?: number;\n /** `number`: inclusive lower bound. */\n min_value?: number;\n /** `number`: inclusive upper bound. */\n max_value?: number;\n /** `number`: maximum number of fractional digits. */\n decimals?: number;\n /** `number`: the value must be a multiple of this step (offset from `min_value`, else 0). */\n steps?: number;\n /** `bloks`: minimum number of nested blocks. */\n minimum?: number;\n /** `bloks`: maximum number of nested blocks. */\n maximum?: number;\n /** `multiasset`: minimum number of assets. */\n minimum_entries?: number;\n /** `multiasset`: maximum number of assets. */\n maximum_entries?: number;\n /** `options`: minimum number of selected options (stored as a string). */\n min_options?: string;\n /** `options`: maximum number of selected options (stored as a string). */\n max_options?: string;\n}\n\n/** A block definition (`defineBlock` result). */\nexport interface SchemaBlockLike {\n name: string;\n fields?: readonly SchemaFieldLike[];\n}\n\n/** A datasource definition (`defineDatasource` result). */\nexport interface SchemaDatasourceLike {\n slug?: string;\n}\n\n/** A field plugin registration (`defineFieldPlugin` result). */\nexport interface FieldPluginLike {\n fieldType: string;\n value: StandardSchemaV1;\n}\n\n/** The schema object accepted by the validators: blocks (required), datasources and field plugins (optional). */\nexport interface SchemaLike {\n blocks: Record<string, SchemaBlockLike> | readonly SchemaBlockLike[];\n datasources?: Record<string, SchemaDatasourceLike> | readonly SchemaDatasourceLike[];\n fieldPlugins?: Record<string, FieldPluginLike> | readonly FieldPluginLike[];\n}\n\n/** Normalizes a record-or-array of entities to an array of values. */\nexport function toValues<T>(input: Record<string, T> | readonly T[] | undefined): T[] {\n if (!input) {\n return [];\n }\n return Array.isArray(input) ? [...input] : Object.values(input as Record<string, T>);\n}\n"],"mappings":";;;;AA6EA,SAAgB,SAAY,OAA0D;AACpF,KAAI,CAAC,MACH,QAAO,EAAE;AAEX,QAAO,MAAM,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,GAAG,OAAO,OAAO,MAA2B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { FieldType } from "../generated/types/field.cjs";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/validators/shapes.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Loose structural views of the content-shape definitions, used internally by
|
|
7
|
+
* the validators. A real `Block` / `Datasource` (from the `define*` helpers) is
|
|
8
|
+
* structurally assignable to these, but they also tolerate the plain objects a
|
|
9
|
+
* validator may receive at runtime.
|
|
10
|
+
*/
|
|
11
|
+
/** A single field within a block's `fields` array. */
|
|
12
|
+
interface SchemaFieldLike {
|
|
13
|
+
name: string;
|
|
14
|
+
type: FieldType;
|
|
15
|
+
/** `custom`: the field plugin discriminant, matched against registered `fieldPlugins`. */
|
|
16
|
+
field_type?: string;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
/** Normalized block-name references for `bloks` fields. */
|
|
19
|
+
allow?: readonly string[];
|
|
20
|
+
/** Normalized datasource slug for option/options fields. */
|
|
21
|
+
datasource?: string;
|
|
22
|
+
/** `text`/`textarea`/`markdown`: maximum string length. */
|
|
23
|
+
max_length?: number;
|
|
24
|
+
/** `text`/`textarea`: legacy alias for `max_length`. */
|
|
25
|
+
maxlength?: number;
|
|
26
|
+
/** `text`/`textarea`: minimum string length. */
|
|
27
|
+
minlength?: number;
|
|
28
|
+
/** `number`: inclusive lower bound. */
|
|
29
|
+
min_value?: number;
|
|
30
|
+
/** `number`: inclusive upper bound. */
|
|
31
|
+
max_value?: number;
|
|
32
|
+
/** `number`: maximum number of fractional digits. */
|
|
33
|
+
decimals?: number;
|
|
34
|
+
/** `number`: the value must be a multiple of this step (offset from `min_value`, else 0). */
|
|
35
|
+
steps?: number;
|
|
36
|
+
/** `bloks`: minimum number of nested blocks. */
|
|
37
|
+
minimum?: number;
|
|
38
|
+
/** `bloks`: maximum number of nested blocks. */
|
|
39
|
+
maximum?: number;
|
|
40
|
+
/** `multiasset`: minimum number of assets. */
|
|
41
|
+
minimum_entries?: number;
|
|
42
|
+
/** `multiasset`: maximum number of assets. */
|
|
43
|
+
maximum_entries?: number;
|
|
44
|
+
/** `options`: minimum number of selected options (stored as a string). */
|
|
45
|
+
min_options?: string;
|
|
46
|
+
/** `options`: maximum number of selected options (stored as a string). */
|
|
47
|
+
max_options?: string;
|
|
48
|
+
}
|
|
49
|
+
/** A block definition (`defineBlock` result). */
|
|
50
|
+
interface SchemaBlockLike {
|
|
51
|
+
name: string;
|
|
52
|
+
fields?: readonly SchemaFieldLike[];
|
|
53
|
+
}
|
|
54
|
+
/** A datasource definition (`defineDatasource` result). */
|
|
55
|
+
interface SchemaDatasourceLike {
|
|
56
|
+
slug?: string;
|
|
57
|
+
}
|
|
58
|
+
/** A field plugin registration (`defineFieldPlugin` result). */
|
|
59
|
+
interface FieldPluginLike {
|
|
60
|
+
fieldType: string;
|
|
61
|
+
value: StandardSchemaV1;
|
|
62
|
+
}
|
|
63
|
+
/** The schema object accepted by the validators: blocks (required), datasources and field plugins (optional). */
|
|
64
|
+
interface SchemaLike {
|
|
65
|
+
blocks: Record<string, SchemaBlockLike> | readonly SchemaBlockLike[];
|
|
66
|
+
datasources?: Record<string, SchemaDatasourceLike> | readonly SchemaDatasourceLike[];
|
|
67
|
+
fieldPlugins?: Record<string, FieldPluginLike> | readonly FieldPluginLike[];
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { SchemaBlockLike, SchemaLike };
|
|
71
|
+
//# sourceMappingURL=shapes.d.cts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { FieldType } from "../generated/types/field.mjs";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/validators/shapes.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Loose structural views of the content-shape definitions, used internally by
|
|
7
|
+
* the validators. A real `Block` / `Datasource` (from the `define*` helpers) is
|
|
8
|
+
* structurally assignable to these, but they also tolerate the plain objects a
|
|
9
|
+
* validator may receive at runtime.
|
|
10
|
+
*/
|
|
11
|
+
/** A single field within a block's `fields` array. */
|
|
12
|
+
interface SchemaFieldLike {
|
|
13
|
+
name: string;
|
|
14
|
+
type: FieldType;
|
|
15
|
+
/** `custom`: the field plugin discriminant, matched against registered `fieldPlugins`. */
|
|
16
|
+
field_type?: string;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
/** Normalized block-name references for `bloks` fields. */
|
|
19
|
+
allow?: readonly string[];
|
|
20
|
+
/** Normalized datasource slug for option/options fields. */
|
|
21
|
+
datasource?: string;
|
|
22
|
+
/** `text`/`textarea`/`markdown`: maximum string length. */
|
|
23
|
+
max_length?: number;
|
|
24
|
+
/** `text`/`textarea`: legacy alias for `max_length`. */
|
|
25
|
+
maxlength?: number;
|
|
26
|
+
/** `text`/`textarea`: minimum string length. */
|
|
27
|
+
minlength?: number;
|
|
28
|
+
/** `number`: inclusive lower bound. */
|
|
29
|
+
min_value?: number;
|
|
30
|
+
/** `number`: inclusive upper bound. */
|
|
31
|
+
max_value?: number;
|
|
32
|
+
/** `number`: maximum number of fractional digits. */
|
|
33
|
+
decimals?: number;
|
|
34
|
+
/** `number`: the value must be a multiple of this step (offset from `min_value`, else 0). */
|
|
35
|
+
steps?: number;
|
|
36
|
+
/** `bloks`: minimum number of nested blocks. */
|
|
37
|
+
minimum?: number;
|
|
38
|
+
/** `bloks`: maximum number of nested blocks. */
|
|
39
|
+
maximum?: number;
|
|
40
|
+
/** `multiasset`: minimum number of assets. */
|
|
41
|
+
minimum_entries?: number;
|
|
42
|
+
/** `multiasset`: maximum number of assets. */
|
|
43
|
+
maximum_entries?: number;
|
|
44
|
+
/** `options`: minimum number of selected options (stored as a string). */
|
|
45
|
+
min_options?: string;
|
|
46
|
+
/** `options`: maximum number of selected options (stored as a string). */
|
|
47
|
+
max_options?: string;
|
|
48
|
+
}
|
|
49
|
+
/** A block definition (`defineBlock` result). */
|
|
50
|
+
interface SchemaBlockLike {
|
|
51
|
+
name: string;
|
|
52
|
+
fields?: readonly SchemaFieldLike[];
|
|
53
|
+
}
|
|
54
|
+
/** A datasource definition (`defineDatasource` result). */
|
|
55
|
+
interface SchemaDatasourceLike {
|
|
56
|
+
slug?: string;
|
|
57
|
+
}
|
|
58
|
+
/** A field plugin registration (`defineFieldPlugin` result). */
|
|
59
|
+
interface FieldPluginLike {
|
|
60
|
+
fieldType: string;
|
|
61
|
+
value: StandardSchemaV1;
|
|
62
|
+
}
|
|
63
|
+
/** The schema object accepted by the validators: blocks (required), datasources and field plugins (optional). */
|
|
64
|
+
interface SchemaLike {
|
|
65
|
+
blocks: Record<string, SchemaBlockLike> | readonly SchemaBlockLike[];
|
|
66
|
+
datasources?: Record<string, SchemaDatasourceLike> | readonly SchemaDatasourceLike[];
|
|
67
|
+
fieldPlugins?: Record<string, FieldPluginLike> | readonly FieldPluginLike[];
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { SchemaBlockLike, SchemaLike };
|
|
71
|
+
//# sourceMappingURL=shapes.d.mts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { isRecord } from "../utils/is-record.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/validators/shapes.ts
|
|
4
|
+
/** Normalizes a record-or-array of entities to an array of values. */
|
|
5
|
+
function toValues(input) {
|
|
6
|
+
if (!input) return [];
|
|
7
|
+
return Array.isArray(input) ? [...input] : Object.values(input);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { toValues };
|
|
12
|
+
//# sourceMappingURL=shapes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.mjs","names":[],"sources":["../../src/validators/shapes.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { FieldType } from '../generated/types/field';\n\nexport { isRecord } from '../utils/is-record';\n\n/**\n * Loose structural views of the content-shape definitions, used internally by\n * the validators. A real `Block` / `Datasource` (from the `define*` helpers) is\n * structurally assignable to these, but they also tolerate the plain objects a\n * validator may receive at runtime.\n */\n\n/** A single field within a block's `fields` array. */\nexport interface SchemaFieldLike {\n name: string;\n type: FieldType;\n /** `custom`: the field plugin discriminant, matched against registered `fieldPlugins`. */\n field_type?: string;\n required?: boolean;\n /** Normalized block-name references for `bloks` fields. */\n allow?: readonly string[];\n /** Normalized datasource slug for option/options fields. */\n datasource?: string;\n // Value constraints enforced by `validateStory` (all optional).\n /** `text`/`textarea`/`markdown`: maximum string length. */\n max_length?: number;\n /** `text`/`textarea`: legacy alias for `max_length`. */\n maxlength?: number;\n /** `text`/`textarea`: minimum string length. */\n minlength?: number;\n /** `number`: inclusive lower bound. */\n min_value?: number;\n /** `number`: inclusive upper bound. */\n max_value?: number;\n /** `number`: maximum number of fractional digits. */\n decimals?: number;\n /** `number`: the value must be a multiple of this step (offset from `min_value`, else 0). */\n steps?: number;\n /** `bloks`: minimum number of nested blocks. */\n minimum?: number;\n /** `bloks`: maximum number of nested blocks. */\n maximum?: number;\n /** `multiasset`: minimum number of assets. */\n minimum_entries?: number;\n /** `multiasset`: maximum number of assets. */\n maximum_entries?: number;\n /** `options`: minimum number of selected options (stored as a string). */\n min_options?: string;\n /** `options`: maximum number of selected options (stored as a string). */\n max_options?: string;\n}\n\n/** A block definition (`defineBlock` result). */\nexport interface SchemaBlockLike {\n name: string;\n fields?: readonly SchemaFieldLike[];\n}\n\n/** A datasource definition (`defineDatasource` result). */\nexport interface SchemaDatasourceLike {\n slug?: string;\n}\n\n/** A field plugin registration (`defineFieldPlugin` result). */\nexport interface FieldPluginLike {\n fieldType: string;\n value: StandardSchemaV1;\n}\n\n/** The schema object accepted by the validators: blocks (required), datasources and field plugins (optional). */\nexport interface SchemaLike {\n blocks: Record<string, SchemaBlockLike> | readonly SchemaBlockLike[];\n datasources?: Record<string, SchemaDatasourceLike> | readonly SchemaDatasourceLike[];\n fieldPlugins?: Record<string, FieldPluginLike> | readonly FieldPluginLike[];\n}\n\n/** Normalizes a record-or-array of entities to an array of values. */\nexport function toValues<T>(input: Record<string, T> | readonly T[] | undefined): T[] {\n if (!input) {\n return [];\n }\n return Array.isArray(input) ? [...input] : Object.values(input as Record<string, T>);\n}\n"],"mappings":";;;;AA6EA,SAAgB,SAAY,OAA0D;AACpF,KAAI,CAAC,MACH,QAAO,EAAE;AAEX,QAAO,MAAM,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,GAAG,OAAO,OAAO,MAA2B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/validators/types.d.ts
|
|
2
|
+
/** Severity of a {@link ValidationIssue}. `error` fails validation; `warning` does not. */
|
|
3
|
+
type ValidationSeverity = 'error' | 'warning';
|
|
4
|
+
/** A single problem found by a validator. */
|
|
5
|
+
interface ValidationIssue {
|
|
6
|
+
/** `error` fails validation; `warning` is advisory. */
|
|
7
|
+
severity: ValidationSeverity;
|
|
8
|
+
/** Stable machine-readable identifier, e.g. `unknown_component`, `invalid_value`. */
|
|
9
|
+
code: string;
|
|
10
|
+
/** Location of the problem as a path of keys/indices into the validated input. */
|
|
11
|
+
path: (string | number)[];
|
|
12
|
+
/** The entity the issue concerns, e.g. `schema`, `story`, `block:hero`, `datasource:colors`. */
|
|
13
|
+
entity: string;
|
|
14
|
+
/** Human-readable description. */
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/** The non-throwing result returned by {@link validateSchema} and {@link validateStory}. */
|
|
18
|
+
interface ValidationResult {
|
|
19
|
+
/** `true` when there are no `error`-severity issues (warnings are allowed). */
|
|
20
|
+
ok: boolean;
|
|
21
|
+
issues: ValidationIssue[];
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { ValidationIssue, ValidationResult, ValidationSeverity };
|
|
25
|
+
//# sourceMappingURL=types.d.cts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/validators/types.d.ts
|
|
2
|
+
/** Severity of a {@link ValidationIssue}. `error` fails validation; `warning` does not. */
|
|
3
|
+
type ValidationSeverity = 'error' | 'warning';
|
|
4
|
+
/** A single problem found by a validator. */
|
|
5
|
+
interface ValidationIssue {
|
|
6
|
+
/** `error` fails validation; `warning` is advisory. */
|
|
7
|
+
severity: ValidationSeverity;
|
|
8
|
+
/** Stable machine-readable identifier, e.g. `unknown_component`, `invalid_value`. */
|
|
9
|
+
code: string;
|
|
10
|
+
/** Location of the problem as a path of keys/indices into the validated input. */
|
|
11
|
+
path: (string | number)[];
|
|
12
|
+
/** The entity the issue concerns, e.g. `schema`, `story`, `block:hero`, `datasource:colors`. */
|
|
13
|
+
entity: string;
|
|
14
|
+
/** Human-readable description. */
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/** The non-throwing result returned by {@link validateSchema} and {@link validateStory}. */
|
|
18
|
+
interface ValidationResult {
|
|
19
|
+
/** `true` when there are no `error`-severity issues (warnings are allowed). */
|
|
20
|
+
ok: boolean;
|
|
21
|
+
issues: ValidationIssue[];
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { ValidationIssue, ValidationResult, ValidationSeverity };
|
|
25
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const require_is_record = require('../utils/is-record.cjs');
|
|
2
|
+
const require_shapes = require('./shapes.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/validators/validate-schema.ts
|
|
5
|
+
/**
|
|
6
|
+
* Validates a schema definition without throwing. Checks structural identity
|
|
7
|
+
* (duplicate block names, field names, and datasource slugs) and cross-references
|
|
8
|
+
* (every `allow` entry resolves to a defined block; every field `datasource`
|
|
9
|
+
* resolves to a defined datasource; every `custom` field's `field_type`
|
|
10
|
+
* resolves to a registered field plugin).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const result = validateSchema({ blocks: { hero }, datasources: { colors } });
|
|
14
|
+
* if (!result.ok) console.error(result.issues);
|
|
15
|
+
*/
|
|
16
|
+
function validateSchema(schema) {
|
|
17
|
+
const issues = [];
|
|
18
|
+
const blocks = require_shapes.toValues(schema.blocks);
|
|
19
|
+
const datasources = require_shapes.toValues(schema.datasources);
|
|
20
|
+
const fieldPlugins = require_shapes.toValues(schema.fieldPlugins);
|
|
21
|
+
const fieldPluginTypes = /* @__PURE__ */ new Set();
|
|
22
|
+
for (const plugin of fieldPlugins) {
|
|
23
|
+
const fieldType = plugin?.fieldType;
|
|
24
|
+
if (typeof fieldType === "string") fieldPluginTypes.add(fieldType);
|
|
25
|
+
}
|
|
26
|
+
const datasourceSlugs = /* @__PURE__ */ new Set();
|
|
27
|
+
for (const datasource of datasources) {
|
|
28
|
+
const slug = datasource?.slug;
|
|
29
|
+
if (typeof slug !== "string") continue;
|
|
30
|
+
if (datasourceSlugs.has(slug)) issues.push({
|
|
31
|
+
severity: "error",
|
|
32
|
+
code: "duplicate_datasource_slug",
|
|
33
|
+
path: ["datasources", slug],
|
|
34
|
+
entity: `datasource:${slug}`,
|
|
35
|
+
message: `Duplicate datasource slug "${slug}".`
|
|
36
|
+
});
|
|
37
|
+
datasourceSlugs.add(slug);
|
|
38
|
+
}
|
|
39
|
+
const blockNames = /* @__PURE__ */ new Set();
|
|
40
|
+
for (const block of blocks) {
|
|
41
|
+
const name = block?.name;
|
|
42
|
+
if (typeof name !== "string") continue;
|
|
43
|
+
if (blockNames.has(name)) issues.push({
|
|
44
|
+
severity: "error",
|
|
45
|
+
code: "duplicate_block_name",
|
|
46
|
+
path: ["blocks", name],
|
|
47
|
+
entity: `block:${name}`,
|
|
48
|
+
message: `Duplicate block name "${name}".`
|
|
49
|
+
});
|
|
50
|
+
blockNames.add(name);
|
|
51
|
+
}
|
|
52
|
+
for (const block of blocks) {
|
|
53
|
+
const blockName = typeof block?.name === "string" ? block.name : "";
|
|
54
|
+
const fieldNames = /* @__PURE__ */ new Set();
|
|
55
|
+
const fields = block?.fields ?? [];
|
|
56
|
+
for (let index = 0; index < fields.length; index++) {
|
|
57
|
+
const field = fields[index];
|
|
58
|
+
if (!require_is_record.isRecord(field)) {
|
|
59
|
+
issues.push({
|
|
60
|
+
severity: "error",
|
|
61
|
+
code: "invalid_field",
|
|
62
|
+
path: [
|
|
63
|
+
"blocks",
|
|
64
|
+
blockName,
|
|
65
|
+
index
|
|
66
|
+
],
|
|
67
|
+
entity: `block:${blockName}`,
|
|
68
|
+
message: `Field at index ${index} in block "${blockName}" is not an object.`
|
|
69
|
+
});
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const fieldName = field.name;
|
|
73
|
+
if (typeof fieldName === "string") {
|
|
74
|
+
if (fieldNames.has(fieldName)) issues.push({
|
|
75
|
+
severity: "error",
|
|
76
|
+
code: "duplicate_field_name",
|
|
77
|
+
path: [
|
|
78
|
+
"blocks",
|
|
79
|
+
blockName,
|
|
80
|
+
fieldName
|
|
81
|
+
],
|
|
82
|
+
entity: `block:${blockName}`,
|
|
83
|
+
message: `Duplicate field name "${fieldName}" in block "${blockName}".`
|
|
84
|
+
});
|
|
85
|
+
fieldNames.add(fieldName);
|
|
86
|
+
} else issues.push({
|
|
87
|
+
severity: "error",
|
|
88
|
+
code: "missing_field_name",
|
|
89
|
+
path: [
|
|
90
|
+
"blocks",
|
|
91
|
+
blockName,
|
|
92
|
+
index
|
|
93
|
+
],
|
|
94
|
+
entity: `block:${blockName}`,
|
|
95
|
+
message: `Field at index ${index} in block "${blockName}" is missing a string "name".`
|
|
96
|
+
});
|
|
97
|
+
for (const allowed of field.allow ?? []) if (typeof allowed === "string" && !blockNames.has(allowed)) issues.push({
|
|
98
|
+
severity: "error",
|
|
99
|
+
code: "unresolved_allow",
|
|
100
|
+
path: [
|
|
101
|
+
"blocks",
|
|
102
|
+
blockName,
|
|
103
|
+
fieldName ?? "",
|
|
104
|
+
"allow"
|
|
105
|
+
],
|
|
106
|
+
entity: `block:${blockName}`,
|
|
107
|
+
message: `Field "${fieldName}" allows unknown block "${allowed}".`
|
|
108
|
+
});
|
|
109
|
+
const datasource = field.datasource;
|
|
110
|
+
if (typeof datasource === "string" && !datasourceSlugs.has(datasource)) issues.push({
|
|
111
|
+
severity: "error",
|
|
112
|
+
code: "unresolved_datasource",
|
|
113
|
+
path: [
|
|
114
|
+
"blocks",
|
|
115
|
+
blockName,
|
|
116
|
+
fieldName ?? "",
|
|
117
|
+
"datasource"
|
|
118
|
+
],
|
|
119
|
+
entity: `block:${blockName}`,
|
|
120
|
+
message: `Field "${fieldName}" references unknown datasource "${datasource}".`
|
|
121
|
+
});
|
|
122
|
+
const fieldType = field.field_type;
|
|
123
|
+
if (field.type === "custom" && typeof fieldType === "string" && !fieldPluginTypes.has(fieldType)) issues.push({
|
|
124
|
+
severity: "error",
|
|
125
|
+
code: "unresolved_field_plugin",
|
|
126
|
+
path: [
|
|
127
|
+
"blocks",
|
|
128
|
+
blockName,
|
|
129
|
+
fieldName ?? "",
|
|
130
|
+
"field_type"
|
|
131
|
+
],
|
|
132
|
+
entity: `block:${blockName}`,
|
|
133
|
+
message: `Field "${fieldName}" references unregistered field plugin "${fieldType}".`
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
ok: issues.every((issue) => issue.severity !== "error"),
|
|
139
|
+
issues
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
//#endregion
|
|
144
|
+
exports.validateSchema = validateSchema;
|
|
145
|
+
//# sourceMappingURL=validate-schema.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-schema.cjs","names":["toValues","isRecord"],"sources":["../../src/validators/validate-schema.ts"],"sourcesContent":["import type { SchemaLike } from './shapes';\nimport type { ValidationIssue, ValidationResult } from './types';\nimport { isRecord, toValues } from './shapes';\n\n/**\n * Validates a schema definition without throwing. Checks structural identity\n * (duplicate block names, field names, and datasource slugs) and cross-references\n * (every `allow` entry resolves to a defined block; every field `datasource`\n * resolves to a defined datasource; every `custom` field's `field_type`\n * resolves to a registered field plugin).\n *\n * @example\n * const result = validateSchema({ blocks: { hero }, datasources: { colors } });\n * if (!result.ok) console.error(result.issues);\n */\nexport function validateSchema(schema: SchemaLike): ValidationResult {\n const issues: ValidationIssue[] = [];\n const blocks = toValues(schema.blocks);\n const datasources = toValues(schema.datasources);\n const fieldPlugins = toValues(schema.fieldPlugins);\n\n const fieldPluginTypes = new Set<string>();\n for (const plugin of fieldPlugins) {\n const fieldType = plugin?.fieldType;\n if (typeof fieldType === 'string') {\n fieldPluginTypes.add(fieldType);\n }\n }\n\n const datasourceSlugs = new Set<string>();\n for (const datasource of datasources) {\n const slug = datasource?.slug;\n if (typeof slug !== 'string') {\n continue;\n }\n if (datasourceSlugs.has(slug)) {\n issues.push({\n severity: 'error',\n code: 'duplicate_datasource_slug',\n path: ['datasources', slug],\n entity: `datasource:${slug}`,\n message: `Duplicate datasource slug \"${slug}\".`,\n });\n }\n datasourceSlugs.add(slug);\n }\n\n const blockNames = new Set<string>();\n for (const block of blocks) {\n const name = block?.name;\n if (typeof name !== 'string') {\n continue;\n }\n if (blockNames.has(name)) {\n issues.push({\n severity: 'error',\n code: 'duplicate_block_name',\n path: ['blocks', name],\n entity: `block:${name}`,\n message: `Duplicate block name \"${name}\".`,\n });\n }\n blockNames.add(name);\n }\n\n // Field-level checks run after the name/slug sets are fully populated so that\n // forward and circular references (resolved by name) validate correctly.\n for (const block of blocks) {\n const blockName = typeof block?.name === 'string' ? block.name : '';\n const fieldNames = new Set<string>();\n const fields = block?.fields ?? [];\n for (let index = 0; index < fields.length; index++) {\n const field = fields[index];\n // Flag malformed fields the wire mapper would otherwise silently drop:\n // a non-object entry, or one without a string `name` (its mapping key).\n if (!isRecord(field)) {\n issues.push({\n severity: 'error',\n code: 'invalid_field',\n path: ['blocks', blockName, index],\n entity: `block:${blockName}`,\n message: `Field at index ${index} in block \"${blockName}\" is not an object.`,\n });\n continue;\n }\n const fieldName = field.name;\n if (typeof fieldName === 'string') {\n if (fieldNames.has(fieldName)) {\n issues.push({\n severity: 'error',\n code: 'duplicate_field_name',\n path: ['blocks', blockName, fieldName],\n entity: `block:${blockName}`,\n message: `Duplicate field name \"${fieldName}\" in block \"${blockName}\".`,\n });\n }\n fieldNames.add(fieldName);\n }\n else {\n issues.push({\n severity: 'error',\n code: 'missing_field_name',\n path: ['blocks', blockName, index],\n entity: `block:${blockName}`,\n message: `Field at index ${index} in block \"${blockName}\" is missing a string \"name\".`,\n });\n }\n\n for (const allowed of field.allow ?? []) {\n if (typeof allowed === 'string' && !blockNames.has(allowed)) {\n issues.push({\n severity: 'error',\n code: 'unresolved_allow',\n path: ['blocks', blockName, fieldName ?? '', 'allow'],\n entity: `block:${blockName}`,\n message: `Field \"${fieldName}\" allows unknown block \"${allowed}\".`,\n });\n }\n }\n\n const datasource = field.datasource;\n if (typeof datasource === 'string' && !datasourceSlugs.has(datasource)) {\n issues.push({\n severity: 'error',\n code: 'unresolved_datasource',\n path: ['blocks', blockName, fieldName ?? '', 'datasource'],\n entity: `block:${blockName}`,\n message: `Field \"${fieldName}\" references unknown datasource \"${datasource}\".`,\n });\n }\n\n const fieldType = field.field_type;\n if (field.type === 'custom' && typeof fieldType === 'string' && !fieldPluginTypes.has(fieldType)) {\n issues.push({\n severity: 'error',\n code: 'unresolved_field_plugin',\n path: ['blocks', blockName, fieldName ?? '', 'field_type'],\n entity: `block:${blockName}`,\n message: `Field \"${fieldName}\" references unregistered field plugin \"${fieldType}\".`,\n });\n }\n }\n }\n\n return { ok: issues.every(issue => issue.severity !== 'error'), issues };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgB,eAAe,QAAsC;CACnE,MAAM,SAA4B,EAAE;CACpC,MAAM,SAASA,wBAAS,OAAO,OAAO;CACtC,MAAM,cAAcA,wBAAS,OAAO,YAAY;CAChD,MAAM,eAAeA,wBAAS,OAAO,aAAa;CAElD,MAAM,mCAAmB,IAAI,KAAa;AAC1C,MAAK,MAAM,UAAU,cAAc;EACjC,MAAM,YAAY,QAAQ;AAC1B,MAAI,OAAO,cAAc,SACvB,kBAAiB,IAAI,UAAU;;CAInC,MAAM,kCAAkB,IAAI,KAAa;AACzC,MAAK,MAAM,cAAc,aAAa;EACpC,MAAM,OAAO,YAAY;AACzB,MAAI,OAAO,SAAS,SAClB;AAEF,MAAI,gBAAgB,IAAI,KAAK,CAC3B,QAAO,KAAK;GACV,UAAU;GACV,MAAM;GACN,MAAM,CAAC,eAAe,KAAK;GAC3B,QAAQ,cAAc;GACtB,SAAS,8BAA8B,KAAK;GAC7C,CAAC;AAEJ,kBAAgB,IAAI,KAAK;;CAG3B,MAAM,6BAAa,IAAI,KAAa;AACpC,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,OAAO;AACpB,MAAI,OAAO,SAAS,SAClB;AAEF,MAAI,WAAW,IAAI,KAAK,CACtB,QAAO,KAAK;GACV,UAAU;GACV,MAAM;GACN,MAAM,CAAC,UAAU,KAAK;GACtB,QAAQ,SAAS;GACjB,SAAS,yBAAyB,KAAK;GACxC,CAAC;AAEJ,aAAW,IAAI,KAAK;;AAKtB,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,YAAY,OAAO,OAAO,SAAS,WAAW,MAAM,OAAO;EACjE,MAAM,6BAAa,IAAI,KAAa;EACpC,MAAM,SAAS,OAAO,UAAU,EAAE;AAClC,OAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS;GAClD,MAAM,QAAQ,OAAO;AAGrB,OAAI,CAACC,2BAAS,MAAM,EAAE;AACpB,WAAO,KAAK;KACV,UAAU;KACV,MAAM;KACN,MAAM;MAAC;MAAU;MAAW;MAAM;KAClC,QAAQ,SAAS;KACjB,SAAS,kBAAkB,MAAM,aAAa,UAAU;KACzD,CAAC;AACF;;GAEF,MAAM,YAAY,MAAM;AACxB,OAAI,OAAO,cAAc,UAAU;AACjC,QAAI,WAAW,IAAI,UAAU,CAC3B,QAAO,KAAK;KACV,UAAU;KACV,MAAM;KACN,MAAM;MAAC;MAAU;MAAW;MAAU;KACtC,QAAQ,SAAS;KACjB,SAAS,yBAAyB,UAAU,cAAc,UAAU;KACrE,CAAC;AAEJ,eAAW,IAAI,UAAU;SAGzB,QAAO,KAAK;IACV,UAAU;IACV,MAAM;IACN,MAAM;KAAC;KAAU;KAAW;KAAM;IAClC,QAAQ,SAAS;IACjB,SAAS,kBAAkB,MAAM,aAAa,UAAU;IACzD,CAAC;AAGJ,QAAK,MAAM,WAAW,MAAM,SAAS,EAAE,CACrC,KAAI,OAAO,YAAY,YAAY,CAAC,WAAW,IAAI,QAAQ,CACzD,QAAO,KAAK;IACV,UAAU;IACV,MAAM;IACN,MAAM;KAAC;KAAU;KAAW,aAAa;KAAI;KAAQ;IACrD,QAAQ,SAAS;IACjB,SAAS,UAAU,UAAU,0BAA0B,QAAQ;IAChE,CAAC;GAIN,MAAM,aAAa,MAAM;AACzB,OAAI,OAAO,eAAe,YAAY,CAAC,gBAAgB,IAAI,WAAW,CACpE,QAAO,KAAK;IACV,UAAU;IACV,MAAM;IACN,MAAM;KAAC;KAAU;KAAW,aAAa;KAAI;KAAa;IAC1D,QAAQ,SAAS;IACjB,SAAS,UAAU,UAAU,mCAAmC,WAAW;IAC5E,CAAC;GAGJ,MAAM,YAAY,MAAM;AACxB,OAAI,MAAM,SAAS,YAAY,OAAO,cAAc,YAAY,CAAC,iBAAiB,IAAI,UAAU,CAC9F,QAAO,KAAK;IACV,UAAU;IACV,MAAM;IACN,MAAM;KAAC;KAAU;KAAW,aAAa;KAAI;KAAa;IAC1D,QAAQ,SAAS;IACjB,SAAS,UAAU,UAAU,0CAA0C,UAAU;IAClF,CAAC;;;AAKR,QAAO;EAAE,IAAI,OAAO,OAAM,UAAS,MAAM,aAAa,QAAQ;EAAE;EAAQ"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SchemaLike } from "./shapes.cjs";
|
|
2
|
+
import { ValidationResult } from "./types.cjs";
|
|
3
|
+
|
|
4
|
+
//#region src/validators/validate-schema.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Validates a schema definition without throwing. Checks structural identity
|
|
7
|
+
* (duplicate block names, field names, and datasource slugs) and cross-references
|
|
8
|
+
* (every `allow` entry resolves to a defined block; every field `datasource`
|
|
9
|
+
* resolves to a defined datasource; every `custom` field's `field_type`
|
|
10
|
+
* resolves to a registered field plugin).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const result = validateSchema({ blocks: { hero }, datasources: { colors } });
|
|
14
|
+
* if (!result.ok) console.error(result.issues);
|
|
15
|
+
*/
|
|
16
|
+
declare function validateSchema(schema: SchemaLike): ValidationResult;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { validateSchema };
|
|
19
|
+
//# sourceMappingURL=validate-schema.d.cts.map
|