@pwfabric/authoring 0.0.0-stage → 1.0.0-rc.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.
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Validation Utilities
3
+ *
4
+ * Schema validation utilities for custom blocks.
5
+ *
6
+ * @module @pwfabric/authoring/validation
7
+ */
8
+ // ============================================================
9
+ // PROPS VALIDATION
10
+ // ============================================================
11
+ /**
12
+ * Validate props against a Zod schema
13
+ *
14
+ * @param props - The props to validate
15
+ * @param schema - The Zod schema to validate against
16
+ * @returns Validation result with validated props or errors
17
+ */
18
+ export function validateProps(props, schema) {
19
+ const result = schema.safeParse(props);
20
+ if (result.success) {
21
+ return {
22
+ valid: true,
23
+ props: result.data,
24
+ errors: [],
25
+ };
26
+ }
27
+ const errors = result.error.errors.map((e) => ({
28
+ code: 'VALIDATION_ERROR',
29
+ message: e.message,
30
+ path: e.path.join('.'),
31
+ }));
32
+ return {
33
+ valid: false,
34
+ errors,
35
+ };
36
+ }
37
+ /**
38
+ * Validate props with defaults applied
39
+ *
40
+ * If validation fails, returns the default props.
41
+ *
42
+ * @param props - The props to validate
43
+ * @param schema - The Zod schema
44
+ * @param defaultProps - Default props to use if validation fails
45
+ * @returns Validated props or defaults
46
+ */
47
+ export function validatePropsWithDefaults(props, schema, defaultProps) {
48
+ const result = schema.safeParse(props);
49
+ return result.success ? result.data : defaultProps;
50
+ }
51
+ // ============================================================
52
+ // BLOCK VALIDATION
53
+ // ============================================================
54
+ /**
55
+ * Validate a block against its definition
56
+ *
57
+ * @param block - The block to validate
58
+ * @param definition - The block definition
59
+ * @returns Validation result
60
+ */
61
+ export function validateBlock(block, definition) {
62
+ const errors = [];
63
+ // Validate type matches
64
+ if (block.type !== definition.type) {
65
+ errors.push({
66
+ code: 'TYPE_MISMATCH',
67
+ message: `Expected block type "${definition.type}", got "${block.type}"`,
68
+ });
69
+ return { valid: false, errors };
70
+ }
71
+ // Validate props
72
+ const propsResult = validateProps(block.props, definition.schema);
73
+ if (!propsResult.valid) {
74
+ errors.push(...propsResult.errors);
75
+ }
76
+ // Validate children constraints
77
+ if (block.children && block.children.length > 0) {
78
+ if (!definition.canHaveChildren) {
79
+ errors.push({
80
+ code: 'CHILDREN_NOT_ALLOWED',
81
+ message: `Block type "${definition.type}" cannot have children`,
82
+ });
83
+ }
84
+ if (definition.allowedChildren && definition.allowedChildren.length > 0) {
85
+ for (const child of block.children) {
86
+ if (!definition.allowedChildren.includes(child.type)) {
87
+ errors.push({
88
+ code: 'INVALID_CHILD_TYPE',
89
+ message: `Block type "${child.type}" is not allowed as a child of "${definition.type}"`,
90
+ path: `children.${child.id}`,
91
+ });
92
+ }
93
+ }
94
+ }
95
+ }
96
+ if (errors.length > 0) {
97
+ return { valid: false, errors };
98
+ }
99
+ return {
100
+ valid: true,
101
+ block: {
102
+ ...block,
103
+ props: propsResult.props ?? block.props,
104
+ },
105
+ errors: [],
106
+ };
107
+ }
108
+ /**
109
+ * Validate a block tree against a registry of definitions
110
+ *
111
+ * Recursively validates all blocks in the tree.
112
+ *
113
+ * @param blocks - The blocks to validate
114
+ * @param registry - The block registry
115
+ * @returns Array of validation errors (empty if all valid)
116
+ */
117
+ export function validateBlockTree(blocks, registry) {
118
+ const errors = [];
119
+ function validateRecursive(block, path) {
120
+ const definition = registry.get(block.type);
121
+ if (!definition) {
122
+ // Not a custom block, skip validation
123
+ // (could be a built-in block type)
124
+ if (block.children) {
125
+ block.children.forEach((child, index) => {
126
+ validateRecursive(child, `${path}.children[${index}]`);
127
+ });
128
+ }
129
+ return;
130
+ }
131
+ const result = validateBlock(block, definition);
132
+ if (!result.valid) {
133
+ errors.push(...result.errors.map((e) => ({
134
+ ...e,
135
+ path: e.path ? `${path}.${e.path}` : path,
136
+ })));
137
+ }
138
+ if (block.children) {
139
+ block.children.forEach((child, index) => {
140
+ validateRecursive(child, `${path}.children[${index}]`);
141
+ });
142
+ }
143
+ }
144
+ blocks.forEach((block, index) => {
145
+ validateRecursive(block, `blocks[${index}]`);
146
+ });
147
+ return errors;
148
+ }
149
+ // ============================================================
150
+ // SCHEMA UTILITIES
151
+ // ============================================================
152
+ /**
153
+ * Create a validation function for a specific block type
154
+ *
155
+ * @param definition - The block definition
156
+ * @returns A validation function
157
+ */
158
+ export function createBlockValidator(definition) {
159
+ return (block) => validateBlock(block, definition);
160
+ }
161
+ /**
162
+ * Create a props validation function for a specific schema
163
+ *
164
+ * @param schema - The Zod schema
165
+ * @returns A validation function
166
+ */
167
+ export function createPropsValidator(schema) {
168
+ return (props) => validateProps(props, schema);
169
+ }
170
+ // ============================================================
171
+ // ERROR FORMATTING
172
+ // ============================================================
173
+ /**
174
+ * Format validation errors as a human-readable string
175
+ *
176
+ * @param errors - The validation errors
177
+ * @returns Formatted error string
178
+ */
179
+ export function formatValidationErrors(errors) {
180
+ if (errors.length === 0) {
181
+ return 'No errors';
182
+ }
183
+ return errors
184
+ .map((e) => {
185
+ const path = e.path ? ` at ${e.path}` : '';
186
+ return `[${e.code}]${path}: ${e.message}`;
187
+ })
188
+ .join('\n');
189
+ }
190
+ /**
191
+ * Check if a validation result has errors
192
+ */
193
+ export function hasErrors(result) {
194
+ return !result.valid && result.errors.length > 0;
195
+ }
196
+ // ============================================================
197
+ // TYPE GUARDS
198
+ // ============================================================
199
+ /**
200
+ * Check if a value is a valid Block
201
+ */
202
+ export function isBlock(value) {
203
+ if (!value || typeof value !== 'object') {
204
+ return false;
205
+ }
206
+ const block = value;
207
+ return (typeof block.id === 'string' &&
208
+ typeof block.type === 'string' &&
209
+ typeof block.props === 'object');
210
+ }
211
+ /**
212
+ * Check if a value is a valid Block array
213
+ */
214
+ export function isBlockArray(value) {
215
+ return Array.isArray(value) && value.every(isBlock);
216
+ }
217
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,60 @@
1
1
  {
2
2
  "name": "@pwfabric/authoring",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Authoring surface for PWFabric — define blocks, factories and capabilities",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "LICENSE",
17
+ "README.md"
18
+ ],
19
+ "dependencies": {
20
+ "zod": "^3.25.76",
21
+ "@pwfabric/contracts": "1.0.0-rc.0",
22
+ "@pwfabric/runtime": "1.0.0-rc.0",
23
+ "@pwfabric/core": "1.0.0-rc.0"
24
+ },
25
+ "peerDependencies": {
26
+ "react": "^19.0.0"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.0.0",
33
+ "@types/react": "^19.0.0",
34
+ "@vitest/coverage-v8": "^2.1.9",
35
+ "typescript": "^5.4.0",
36
+ "vitest": "^2.0.0"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/pwfabric/pwfabric",
41
+ "directory": "packages/authoring"
42
+ },
43
+ "homepage": "https://github.com/pwfabric/pwfabric#readme",
44
+ "bugs": {
45
+ "url": "https://github.com/pwfabric/pwfabric/issues"
46
+ },
47
+ "license": "Apache-2.0",
48
+ "author": "PhiMajor Solutions",
49
+ "scripts": {
50
+ "build": "rm -rf dist tsconfig.tsbuildinfo && tsc",
51
+ "dev": "tsc --watch",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest",
54
+ "test:coverage": "vitest run --coverage",
55
+ "lint": "eslint src",
56
+ "lint:fix": "eslint src --fix",
57
+ "typecheck": "tsc --noEmit",
58
+ "clean": "rm -rf dist"
59
+ }
6
60
  }