@adobe/spectrum-component-api-schemas 1.0.0 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @adobe/spectrum-component-api-schemas
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#523](https://github.com/adobe/spectrum-tokens/pull/523) [`9c5a2ac`](https://github.com/adobe/spectrum-tokens/commit/9c5a2ac5fccb29b6f106396b21d91aab949043d4) Thanks [@GarthDB](https://github.com/GarthDB)! - S2 components batch 1 (part 2)
8
+
9
+ ## Changes
10
+
11
+ ### Properties added
12
+ - component: select-box
13
+ - `body`
14
+
15
+ ### Properties updated
16
+ - component: text-area
17
+ - `errorMessage`
18
+ - removed: `"default": null`
19
+
3
20
  ## 1.0.0
4
21
 
5
22
  ### Major Changes
@@ -9,7 +26,6 @@
9
26
  ## Changes
10
27
 
11
28
  ### Properties Added
12
-
13
29
  - component: search-field
14
30
  - `helpText`
15
31
  - `placeholder`
@@ -29,7 +45,6 @@
29
45
  - `helpText`
30
46
 
31
47
  ### Properties removed
32
-
33
48
  - component: search-field
34
49
  - `isQuiet`
35
50
  - component: text-area
@@ -40,7 +55,6 @@
40
55
  - `isReadOnly`
41
56
 
42
57
  ### Properties updated
43
-
44
58
  - component: meter
45
59
  - `size`:
46
60
  - `enum`: `["small", "large"]` -> `["s", "m", "l", "xl"]`
@@ -54,7 +68,6 @@
54
68
  - `default`: `6` -> `8`
55
69
 
56
70
  ### New Component
57
-
58
71
  - select-box
59
72
 
60
73
  ## 0.0.0
package/ava.config.js ADDED
@@ -0,0 +1,9 @@
1
+ export default {
2
+ files: ["test/**/*.test.js"],
3
+ environmentVariables: {
4
+ NODE_ENV: "test",
5
+ },
6
+ verbose: true,
7
+ failFast: false,
8
+ failWithoutAssertions: true,
9
+ };
package/index.js CHANGED
@@ -87,6 +87,9 @@ export const getSchemaBySlug = async (slug) => {
87
87
  return Object.hasOwn(schema, "slug") && schema.slug === slug;
88
88
  }),
89
89
  );
90
+ if (schema === undefined) {
91
+ throw new Error(`Schema not found for slug: ${slug}`);
92
+ }
90
93
  delete schema.slug;
91
94
  return schema;
92
95
  };
package/moon.yml CHANGED
@@ -22,7 +22,8 @@ tasks:
22
22
  inputs:
23
23
  - "@globs(schemas)"
24
24
  - "@globs(tests)"
25
- - index.js
25
+ - "index.js"
26
+ - "ava.config.js"
26
27
  platform: node
27
28
  test-watch:
28
29
  command:
@@ -30,3 +31,27 @@ tasks:
30
31
  - --watch
31
32
  local: true
32
33
  platform: node
34
+ test-coverage:
35
+ command:
36
+ - c8
37
+ - ava
38
+ local: true
39
+ platform: node
40
+ test-schema-validation:
41
+ command:
42
+ - ava
43
+ - test/schema-validation.test.js
44
+ local: true
45
+ platform: node
46
+ test-integration:
47
+ command:
48
+ - ava
49
+ - test/integration.test.js
50
+ local: true
51
+ platform: node
52
+ test-performance:
53
+ command:
54
+ - ava
55
+ - test/performance.test.js
56
+ local: true
57
+ platform: node
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spectrum-component-api-schemas",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -17,6 +17,9 @@
17
17
  "enum": ["horizontal", "vertical"],
18
18
  "default": "horizontal"
19
19
  },
20
+ "body": {
21
+ "type": "string"
22
+ },
20
23
  "isSelected": {
21
24
  "type": "boolean",
22
25
  "default": false
@@ -34,9 +34,6 @@
34
34
  "enum": ["text", "icon"],
35
35
  "default": "icon"
36
36
  },
37
- "helpText": {
38
- "type": "string"
39
- },
40
37
  "isRequired": {
41
38
  "type": "boolean",
42
39
  "default": false
@@ -65,13 +62,11 @@
65
62
  "type": "number",
66
63
  "description": "If undefined, height is dynamic and grows with input text."
67
64
  },
68
- "description": {
69
- "type": "string",
70
- "default": null
65
+ "helpText": {
66
+ "type": "string"
71
67
  },
72
68
  "errorMessage": {
73
- "type": "string",
74
- "default": null
69
+ "type": "string"
75
70
  },
76
71
  "inputType": {
77
72
  "type": "string",
@@ -34,9 +34,6 @@
34
34
  "enum": ["text", "icon"],
35
35
  "default": "icon"
36
36
  },
37
- "helpText": {
38
- "type": "string"
39
- },
40
37
  "isRequired": {
41
38
  "type": "boolean",
42
39
  "default": false
@@ -58,13 +55,11 @@
58
55
  "type": "boolean",
59
56
  "default": false
60
57
  },
61
- "description": {
62
- "type": "string",
63
- "default": null
58
+ "helpText": {
59
+ "type": "string"
64
60
  },
65
61
  "errorMessage": {
66
- "type": "string",
67
- "default": null
62
+ "type": "string"
68
63
  },
69
64
  "state": {
70
65
  "type": "string",
package/test/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # Component Schemas Testing
2
+
3
+ This directory contains comprehensive tests for the component-schemas package.
4
+
5
+ ## Test Structure
6
+
7
+ ### Core Tests
8
+
9
+ - `index.test.js` - Tests for the main API functions
10
+ - `componentSchemaValidator.test.js` - Legacy schema validation tests
11
+
12
+ ### New Test Suite
13
+
14
+ - `schema-validation.test.js` - Comprehensive schema validation using test utilities
15
+ - `integration.test.js` - Integration tests for full workflow
16
+ - `performance.test.js` - Performance benchmarks
17
+ - `utils/test-helpers.js` - Shared test utilities
18
+
19
+ ## Running Tests
20
+
21
+ ### Using Moon (Recommended)
22
+
23
+ ```bash
24
+ # Run all tests
25
+ moon run component-schemas:test
26
+
27
+ # Run specific test suites
28
+ moon run component-schemas:test-schema-validation
29
+ moon run component-schemas:test-integration
30
+ moon run component-schemas:test-performance
31
+
32
+ # Run with coverage
33
+ moon run component-schemas:test-coverage
34
+
35
+ # Watch mode
36
+ moon run component-schemas:test-watch
37
+ ```
38
+
39
+ ## Test Categories
40
+
41
+ ### 1. Schema Validation Tests
42
+
43
+ - Validates all component schemas against the base component definition
44
+ - Ensures all examples in schemas are valid
45
+ - Checks that type schemas are valid JSON Schema
46
+ - Verifies required metadata is present
47
+
48
+ ### 2. Integration Tests
49
+
50
+ - Tests the full workflow of schema loading and processing
51
+ - Validates API function behavior with real data
52
+ - Ensures data consistency across functions
53
+ - Tests error handling and edge cases
54
+
55
+ ### 3. Performance Tests
56
+
57
+ - Benchmarks function execution times
58
+ - Monitors memory usage
59
+ - Tests concurrent operations
60
+ - Ensures performance meets requirements
61
+
62
+ ## Test Utilities
63
+
64
+ The `utils/test-helpers.js` file provides common utilities:
65
+
66
+ - `readJSON()` - Read and parse JSON files
67
+ - `getSchemaFiles()` - Get schema files using glob patterns
68
+ - `createAjvInstance()` - Create configured Ajv instance
69
+ - `validateSchema()` - Validate schemas with detailed error reporting
70
+ - `validateExamples()` - Validate examples in schemas
71
+
72
+ ## Coverage
73
+
74
+ Test coverage includes:
75
+
76
+ - ✅ All exported functions
77
+ - ✅ Schema validation logic
78
+ - ✅ Error handling
79
+ - ✅ Edge cases
80
+ - ✅ Performance benchmarks
81
+
82
+ ## Adding New Tests
83
+
84
+ 1. Create test file in the appropriate category
85
+ 2. Use test utilities from `utils/test-helpers.js`
86
+ 3. Add descriptive test names and assertions
87
+ 4. Update this README if adding new test categories
88
+ 5. Consider adding performance tests for new functions
89
+
90
+ ## Best Practices
91
+
92
+ - Use descriptive test names that explain the expected behavior
93
+ - Group related tests together
94
+ - Use test utilities for common operations
95
+ - Include both positive and negative test cases
96
+ - Add performance tests for new functions
97
+ - Keep tests focused and independent
@@ -0,0 +1,118 @@
1
+ import test from "ava";
2
+ import {
3
+ getAllSchemas,
4
+ getSchemaBySlug,
5
+ getAllSlugs,
6
+ getSlugFromDocumentationUrl,
7
+ schemaFileNames,
8
+ } from "../index.js";
9
+ import { getSchemaFiles } from "./utils/test-helpers.js";
10
+ import { relative } from "path";
11
+
12
+ test("getAllSchemas should return all schemas with slugs", async (t) => {
13
+ const schemas = await getAllSchemas();
14
+
15
+ t.true(Array.isArray(schemas));
16
+ t.true(schemas.length > 0);
17
+
18
+ // Check that schemas with documentation URLs have slugs
19
+ const schemasWithSlugs = schemas.filter((schema) => schema.slug);
20
+ t.true(schemasWithSlugs.length > 0);
21
+
22
+ // Verify slug format
23
+ for (const schema of schemasWithSlugs) {
24
+ t.true(typeof schema.slug === "string");
25
+ t.true(schema.slug.length > 0);
26
+ }
27
+ });
28
+
29
+ test("getAllSlugs should return all component slugs", async (t) => {
30
+ const slugs = await getAllSlugs();
31
+
32
+ t.true(Array.isArray(slugs));
33
+ t.true(slugs.length > 0);
34
+
35
+ // Verify all slugs are unique
36
+ const uniqueSlugs = new Set(slugs);
37
+ t.is(uniqueSlugs.size, slugs.length, "All slugs should be unique");
38
+
39
+ // Verify slug format (should be kebab-case)
40
+ for (const slug of slugs) {
41
+ t.true(/^[a-z0-9-]+$/.test(slug), `Slug "${slug}" should be kebab-case`);
42
+ }
43
+ });
44
+
45
+ test("getSchemaBySlug should return correct schema", async (t) => {
46
+ const slugs = await getAllSlugs();
47
+
48
+ if (slugs.length === 0) {
49
+ t.skip("No slugs available for testing");
50
+ return;
51
+ }
52
+
53
+ const testSlug = slugs[0];
54
+ const schema = await getSchemaBySlug(testSlug);
55
+
56
+ t.truthy(schema);
57
+ t.true(typeof schema === "object");
58
+ t.true(Object.hasOwn(schema.meta, "documentationUrl"));
59
+
60
+ // Verify the slug was extracted correctly
61
+ const expectedSlug = getSlugFromDocumentationUrl(
62
+ schema.meta.documentationUrl,
63
+ );
64
+ t.is(expectedSlug, testSlug);
65
+ });
66
+
67
+ test("getSlugFromDocumentationUrl should handle various URL formats", (t) => {
68
+ const testCases = [
69
+ { url: "https://spectrum.adobe.com/page/tooltip/", expected: "tooltip" },
70
+ { url: "https://spectrum.adobe.com/page/tooltip", expected: "tooltip" },
71
+ {
72
+ url: "https://spectrum.adobe.com/page/action-bar/",
73
+ expected: "action-bar",
74
+ },
75
+ { url: "https://spectrum.adobe.com/page/button/", expected: "button" },
76
+ { url: "https://spectrum.adobe.com/page/button", expected: "button" },
77
+ ];
78
+
79
+ for (const { url, expected } of testCases) {
80
+ const result = getSlugFromDocumentationUrl(url);
81
+ t.is(result, expected, `Failed for URL: ${url}`);
82
+ }
83
+ });
84
+
85
+ test("schemaFileNames should match actual files on disk", async (t) => {
86
+ const actualFiles = await getSchemaFiles();
87
+
88
+ t.is(schemaFileNames.length, actualFiles.length);
89
+
90
+ // Verify all files in schemaFileNames exist
91
+ for (const fileName of schemaFileNames) {
92
+ const relativePath = relative(process.cwd(), fileName);
93
+ t.true(
94
+ actualFiles.includes(relativePath),
95
+ `File ${fileName} not found on disk`,
96
+ );
97
+ }
98
+ });
99
+
100
+ test("getAllSchemas should return same number as schemaFileNames", async (t) => {
101
+ const allSchemas = await getAllSchemas();
102
+
103
+ t.is(schemaFileNames.length, allSchemas.length);
104
+ });
105
+
106
+ test("getSchemaBySlug should throw for non-existent slug", async (t) => {
107
+ const nonExistentSlug = "non-existent-component";
108
+
109
+ await t.throwsAsync(
110
+ async () => {
111
+ const schema = await getSchemaBySlug(nonExistentSlug);
112
+ if (!schema) {
113
+ throw new Error("Schema not found");
114
+ }
115
+ },
116
+ { message: /Schema not found/ },
117
+ );
118
+ });
@@ -0,0 +1,121 @@
1
+ import test from "ava";
2
+ import { performance } from "perf_hooks";
3
+ import {
4
+ getAllSchemas,
5
+ getSchemaBySlug,
6
+ getAllSlugs,
7
+ getSchemaFile,
8
+ } from "../index.js";
9
+
10
+ test("getAllSchemas should complete within reasonable time", async (t) => {
11
+ const start = performance.now();
12
+ const schemas = await getAllSchemas();
13
+ const end = performance.now();
14
+ const duration = end - start;
15
+
16
+ // Should complete within 1 second
17
+ t.true(
18
+ duration < 1000,
19
+ `getAllSchemas took ${duration.toFixed(2)}ms, expected < 1000ms`,
20
+ );
21
+ t.true(schemas.length > 0);
22
+ });
23
+
24
+ test("getAllSlugs should complete within reasonable time", async (t) => {
25
+ const start = performance.now();
26
+ const slugs = await getAllSlugs();
27
+ const end = performance.now();
28
+ const duration = end - start;
29
+
30
+ // Should complete within 500ms
31
+ t.true(
32
+ duration < 500,
33
+ `getAllSlugs took ${duration.toFixed(2)}ms, expected < 500ms`,
34
+ );
35
+ t.true(slugs.length > 0);
36
+ });
37
+
38
+ test("getSchemaBySlug should complete within reasonable time", async (t) => {
39
+ const slugs = await getAllSlugs();
40
+
41
+ if (slugs.length === 0) {
42
+ t.skip("No slugs available for testing");
43
+ return;
44
+ }
45
+
46
+ const testSlug = slugs[0];
47
+ const start = performance.now();
48
+ const schema = await getSchemaBySlug(testSlug);
49
+ const end = performance.now();
50
+ const duration = end - start;
51
+
52
+ // Should complete within 100ms
53
+ t.true(
54
+ duration < 100,
55
+ `getSchemaBySlug took ${duration.toFixed(2)}ms, expected < 100ms`,
56
+ );
57
+ t.truthy(schema);
58
+ });
59
+
60
+ test("getSchemaFile should complete within reasonable time", async (t) => {
61
+ const start = performance.now();
62
+ const schema = await getSchemaFile("component.json");
63
+ const end = performance.now();
64
+ const duration = end - start;
65
+
66
+ // Should complete within 50ms
67
+ t.true(
68
+ duration < 50,
69
+ `getSchemaFile took ${duration.toFixed(2)}ms, expected < 100ms`,
70
+ );
71
+ t.truthy(schema);
72
+ });
73
+
74
+ test("multiple concurrent getSchemaBySlug calls should complete efficiently", async (t) => {
75
+ const slugs = await getAllSlugs();
76
+
77
+ if (slugs.length < 3) {
78
+ t.skip("Not enough slugs for concurrent testing");
79
+ return;
80
+ }
81
+
82
+ const testSlugs = slugs.slice(0, 3);
83
+ const start = performance.now();
84
+
85
+ const results = await Promise.all(
86
+ testSlugs.map((slug) => getSchemaBySlug(slug)),
87
+ );
88
+
89
+ const end = performance.now();
90
+ const duration = end - start;
91
+
92
+ // Should complete within 200ms for 3 concurrent calls
93
+ t.true(
94
+ duration < 200,
95
+ `Concurrent getSchemaBySlug calls took ${duration.toFixed(2)}ms, expected < 200ms`,
96
+ );
97
+ t.is(results.length, 3);
98
+ t.true(results.every((schema) => schema !== null));
99
+ });
100
+
101
+ test("memory usage should be reasonable", async (t) => {
102
+ const initialMemory = process.memoryUsage().heapUsed;
103
+
104
+ // Perform multiple operations
105
+ const schemas = await getAllSchemas();
106
+ const slugs = await getAllSlugs();
107
+
108
+ if (slugs.length > 0) {
109
+ await getSchemaBySlug(slugs[0]);
110
+ }
111
+
112
+ const finalMemory = process.memoryUsage().heapUsed;
113
+ const memoryIncrease = finalMemory - initialMemory;
114
+
115
+ // Memory increase should be less than 10MB
116
+ const memoryIncreaseMB = memoryIncrease / 1024 / 1024;
117
+ t.true(
118
+ memoryIncreaseMB < 10,
119
+ `Memory usage increased by ${memoryIncreaseMB.toFixed(2)}MB, expected < 10MB`,
120
+ );
121
+ });
@@ -0,0 +1,131 @@
1
+ import test from "ava";
2
+ import {
3
+ readJSON,
4
+ getSchemaFiles,
5
+ createAjvInstance,
6
+ validateSchema,
7
+ validateExamples,
8
+ } from "./utils/test-helpers.js";
9
+
10
+ // Setup Ajv instance once for all tests
11
+ let ajv;
12
+
13
+ test.before(async () => {
14
+ ajv = await createAjvInstance();
15
+ });
16
+
17
+ test("component schema should be valid", async (t) => {
18
+ const componentSchema = await readJSON("schemas/component.json");
19
+ const result = validateSchema(componentSchema, ajv);
20
+
21
+ t.true(
22
+ result.valid,
23
+ `Component schema validation failed: ${JSON.stringify(result.errors, null, 2)}`,
24
+ );
25
+ });
26
+
27
+ test("all component schemas should validate against the definition", async (t) => {
28
+ const componentFiles = await getSchemaFiles("schemas/components/*.json");
29
+ const validationResults = [];
30
+
31
+ for (const filePath of componentFiles) {
32
+ const schema = await readJSON(filePath);
33
+ const result = validateSchema(schema, ajv);
34
+
35
+ if (!result.valid) {
36
+ validationResults.push({
37
+ file: filePath,
38
+ errors: result.errors,
39
+ });
40
+ }
41
+ }
42
+
43
+ t.is(
44
+ validationResults.length,
45
+ 0,
46
+ `Schema validation failed for:\n${validationResults
47
+ .map((r) => `${r.file}:\n${JSON.stringify(r.errors, null, 2)}`)
48
+ .join("\n\n")}`,
49
+ );
50
+ });
51
+
52
+ test("all component examples should validate against their schemas", async (t) => {
53
+ const componentFiles = await getSchemaFiles("schemas/components/*.json");
54
+ const validationResults = [];
55
+
56
+ for (const filePath of componentFiles) {
57
+ const schema = await readJSON(filePath);
58
+ const result = validateExamples(schema, ajv);
59
+
60
+ if (!result.valid) {
61
+ validationResults.push({
62
+ file: filePath,
63
+ errors: result.errors,
64
+ });
65
+ }
66
+ }
67
+
68
+ t.is(
69
+ validationResults.length,
70
+ 0,
71
+ `Example validation failed for:\n${validationResults
72
+ .map((r) => `${r.file}:\n${JSON.stringify(r.errors, null, 2)}`)
73
+ .join("\n\n")}`,
74
+ );
75
+ });
76
+
77
+ test("all type schemas should be valid JSON Schema", async (t) => {
78
+ const typeFiles = await getSchemaFiles("schemas/types/*.json");
79
+ const validationResults = [];
80
+
81
+ for (const filePath of typeFiles) {
82
+ const schema = await readJSON(filePath);
83
+ const result = validateSchema(schema, ajv);
84
+
85
+ if (!result.valid) {
86
+ validationResults.push({
87
+ file: filePath,
88
+ errors: result.errors,
89
+ });
90
+ }
91
+ }
92
+
93
+ t.is(
94
+ validationResults.length,
95
+ 0,
96
+ `Type schema validation failed for:\n${validationResults
97
+ .map((r) => `${r.file}:\n${JSON.stringify(r.errors, null, 2)}`)
98
+ .join("\n\n")}`,
99
+ );
100
+ });
101
+
102
+ test("component schemas should have required metadata", async (t) => {
103
+ const componentFiles = await getSchemaFiles("schemas/components/*.json");
104
+ const missingMetadata = [];
105
+
106
+ for (const filePath of componentFiles) {
107
+ const schema = await readJSON(filePath);
108
+
109
+ if (!schema.meta?.category) {
110
+ missingMetadata.push(`${filePath}: missing category`);
111
+ }
112
+
113
+ if (!schema.meta?.documentationUrl) {
114
+ missingMetadata.push(`${filePath}: missing documentationUrl`);
115
+ }
116
+
117
+ if (!schema.title) {
118
+ missingMetadata.push(`${filePath}: missing title`);
119
+ }
120
+
121
+ if (!Object.hasOwn(schema, "description")) {
122
+ missingMetadata.push(`${filePath}: missing description`);
123
+ }
124
+ }
125
+
126
+ t.is(
127
+ missingMetadata.length,
128
+ 0,
129
+ `Missing required metadata:\n${missingMetadata.join("\n")}`,
130
+ );
131
+ });
@@ -0,0 +1,89 @@
1
+ import { readFile } from "fs/promises";
2
+ import { glob } from "glob";
3
+ import { resolve } from "path";
4
+ import Ajv from "ajv/dist/2020.js";
5
+ import addFormats from "ajv-formats";
6
+
7
+ /**
8
+ * Read and parse a JSON file
9
+ * @param {string} filePath - Path to the JSON file
10
+ * @returns {Promise<Object>} Parsed JSON object
11
+ */
12
+ export const readJSON = async (filePath) =>
13
+ JSON.parse(await readFile(filePath, "utf8"));
14
+
15
+ /**
16
+ * Get all schema files matching a pattern
17
+ * @param {string} pattern - Glob pattern for schema files
18
+ * @returns {Promise<string[]>} Array of file paths
19
+ */
20
+ export const getSchemaFiles = async (pattern = "schemas/**/*.json") =>
21
+ await glob(pattern);
22
+
23
+ /**
24
+ * Create a configured Ajv instance with common schemas
25
+ * @returns {Promise<Ajv>} Configured Ajv instance
26
+ */
27
+ export const createAjvInstance = async () => {
28
+ const ajv = new Ajv({
29
+ allErrors: true,
30
+ verbose: true,
31
+ strict: false,
32
+ });
33
+
34
+ addFormats(ajv);
35
+
36
+ // Add component schema as meta schema
37
+ const componentSchema = await readJSON("schemas/component.json");
38
+ ajv.addMetaSchema(componentSchema);
39
+
40
+ // Add type schemas
41
+ const typeSchemaFiles = await glob("schemas/types/*.json");
42
+ for (const schemaFile of typeSchemaFiles) {
43
+ const schema = await readJSON(schemaFile);
44
+ ajv.addSchema(schema);
45
+ }
46
+
47
+ return ajv;
48
+ };
49
+
50
+ /**
51
+ * Validate a schema against the component definition
52
+ * @param {Object} schema - Schema to validate
53
+ * @param {Ajv} ajv - Ajv instance
54
+ * @returns {Object} Validation result with errors if any
55
+ */
56
+ export const validateSchema = (schema, ajv) => {
57
+ const valid = ajv.validateSchema(schema);
58
+ return {
59
+ valid,
60
+ errors: ajv.errors || [],
61
+ };
62
+ };
63
+
64
+ /**
65
+ * Validate examples in a schema
66
+ * @param {Object} schema - Schema containing examples
67
+ * @param {Ajv} ajv - Ajv instance
68
+ * @returns {Object} Validation result with errors if any
69
+ */
70
+ export const validateExamples = (schema, ajv) => {
71
+ const validate = ajv.compile(schema);
72
+ const examples = schema.examples || [];
73
+ const errors = [];
74
+
75
+ for (const example of examples) {
76
+ const valid = validate(example);
77
+ if (!valid) {
78
+ errors.push({
79
+ example,
80
+ errors: validate.errors,
81
+ });
82
+ }
83
+ }
84
+
85
+ return {
86
+ valid: errors.length === 0,
87
+ errors,
88
+ };
89
+ };