Skip to content

Commit 270d189

Browse files
authored
Merge pull request #1 from VirtusLab-Open-Source/feat/generate-component-schema
feat: support for component schemas
2 parents b88c296 + fc81ab4 commit 270d189

File tree

6 files changed

+438
-10
lines changed

6 files changed

+438
-10
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sensinum/astro-strapi-loader",
3-
"version": "1.0.7",
3+
"version": "1.0.8",
44
"description": "Astro loader for Strapi CMS",
55
"keywords": [
66
"astro",

src/types/strapi.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ export interface StrapiContentType {
3434
};
3535
}
3636

37+
export interface StrapiComponent {
38+
uid: string;
39+
category: string;
40+
apiId: string;
41+
schema: {
42+
displayName: string;
43+
description: string;
44+
icon: string;
45+
collectionName: string;
46+
attributes: Record<string, StrapiAttribute>;
47+
}
48+
}
49+
3750
export interface StrapiAttribute {
3851
type: string;
3952
required?: boolean;

src/utils/__tests__/schema.test.ts

Lines changed: 194 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { StrapiSchemaGenerator } from "../schema";
2-
import type { StrapiContentType } from "../../types/strapi";
2+
import type { StrapiContentType, StrapiComponent } from "../../types/strapi";
33

44
describe("StrapiSchemaGenerator", () => {
55
const mockContentType: StrapiContentType = {
@@ -28,14 +28,73 @@ describe("StrapiSchemaGenerator", () => {
2828
type: "uid",
2929
targetField: "title",
3030
},
31+
hero: {
32+
type: "component",
33+
repeatable: false,
34+
component: "layout.hero",
35+
},
36+
testimonials: {
37+
type: "component",
38+
repeatable: true,
39+
component: "content.testimonial",
40+
},
3141
},
3242
},
3343
};
3444

45+
const mockComponents: Array<StrapiComponent> = [
46+
{
47+
uid: "layout.hero",
48+
category: "layout",
49+
apiId: "hero",
50+
schema: {
51+
displayName: "Hero",
52+
description: "Hero section component",
53+
icon: "star",
54+
collectionName: "components_layout_heroes",
55+
attributes: {
56+
title: {
57+
type: "string",
58+
required: true,
59+
},
60+
description: {
61+
type: "text",
62+
required: false,
63+
},
64+
},
65+
},
66+
},
67+
{
68+
uid: "content.testimonial",
69+
category: "content",
70+
apiId: "testimonial",
71+
schema: {
72+
displayName: "Testimonial",
73+
description: "Customer testimonial",
74+
icon: "quote",
75+
collectionName: "components_content_testimonials",
76+
attributes: {
77+
name: {
78+
type: "string",
79+
required: true,
80+
},
81+
content: {
82+
type: "string",
83+
required: true,
84+
},
85+
rating: {
86+
type: "integer",
87+
required: false,
88+
},
89+
},
90+
},
91+
},
92+
];
93+
3594
let generator: StrapiSchemaGenerator;
3695

3796
beforeEach(() => {
38-
generator = new StrapiSchemaGenerator([mockContentType]);
97+
generator = new StrapiSchemaGenerator([mockContentType], mockComponents);
3998
});
4099

41100
describe("generateSchema", () => {
@@ -61,4 +120,137 @@ describe("StrapiSchemaGenerator", () => {
61120
expect(schemas["articles"].shape).toHaveProperty("title");
62121
});
63122
});
123+
124+
describe("component handling", () => {
125+
it("should generate schema for non-repeatable component", () => {
126+
const schema = generator.generateSchema("article");
127+
expect(schema.shape).toHaveProperty("hero");
128+
129+
// Test that component schema is generated correctly
130+
const heroField = schema.shape.hero;
131+
expect(heroField).toBeDefined();
132+
});
133+
134+
it("should generate schema for repeatable component", () => {
135+
const schema = generator.generateSchema("article");
136+
expect(schema.shape).toHaveProperty("testimonials");
137+
138+
// Test that repeatable component schema is an array
139+
const testimonialsField = schema.shape.testimonials;
140+
expect(testimonialsField).toBeDefined();
141+
});
142+
143+
it("should ignore missing component and log warning", () => {
144+
const contentTypeWithMissingComponent: StrapiContentType = {
145+
apiID: "test",
146+
uid: "api::test.test",
147+
plugin: undefined,
148+
schema: {
149+
uid: "api::test.test",
150+
kind: "collectionType",
151+
collectionName: "tests",
152+
singularName: "test",
153+
pluralName: "tests",
154+
displayName: "Test",
155+
draftAndPublish: true,
156+
pluginOptions: {},
157+
visible: true,
158+
attributes: {
159+
title: {
160+
type: "string",
161+
required: true,
162+
},
163+
missingComponent: {
164+
type: "component",
165+
repeatable: false,
166+
component: "missing.component",
167+
},
168+
},
169+
},
170+
};
171+
172+
const testGenerator = new StrapiSchemaGenerator([contentTypeWithMissingComponent], mockComponents);
173+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
174+
175+
const schema = testGenerator.generateSchema("test");
176+
177+
// Schema should be generated successfully without the missing component
178+
expect(schema).toBeDefined();
179+
expect(schema.shape).toHaveProperty("title");
180+
expect(schema.shape).not.toHaveProperty("missingComponent");
181+
182+
// Warning should be logged
183+
expect(consoleSpy).toHaveBeenCalledWith(
184+
"Error generating attribute schema",
185+
expect.any(Error)
186+
);
187+
188+
consoleSpy.mockRestore();
189+
});
190+
191+
it("should ignore component type without component name and log warning", () => {
192+
const contentTypeWithInvalidComponent: StrapiContentType = {
193+
apiID: "test",
194+
uid: "api::test.test",
195+
plugin: undefined,
196+
schema: {
197+
uid: "api::test.test",
198+
kind: "collectionType",
199+
collectionName: "tests",
200+
singularName: "test",
201+
pluralName: "tests",
202+
displayName: "Test",
203+
draftAndPublish: true,
204+
pluginOptions: {},
205+
visible: true,
206+
attributes: {
207+
title: {
208+
type: "string",
209+
required: true,
210+
},
211+
invalidComponent: {
212+
type: "component",
213+
repeatable: false,
214+
// missing component property
215+
},
216+
},
217+
},
218+
};
219+
220+
const testGenerator = new StrapiSchemaGenerator([contentTypeWithInvalidComponent], mockComponents);
221+
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
222+
223+
const schema = testGenerator.generateSchema("test");
224+
225+
// Schema should be generated successfully without the invalid component
226+
expect(schema).toBeDefined();
227+
expect(schema.shape).toHaveProperty("title");
228+
expect(schema.shape).not.toHaveProperty("invalidComponent");
229+
230+
// Warning should be logged
231+
expect(consoleSpy).toHaveBeenCalledWith(
232+
"Error generating attribute schema",
233+
expect.any(Error)
234+
);
235+
236+
consoleSpy.mockRestore();
237+
});
238+
});
239+
240+
describe("constructor with components", () => {
241+
it("should initialize with empty components array", () => {
242+
const generatorWithEmptyComponents = new StrapiSchemaGenerator([mockContentType], []);
243+
expect(generatorWithEmptyComponents).toBeDefined();
244+
});
245+
246+
it("should initialize with components array", () => {
247+
const generatorWithComponents = new StrapiSchemaGenerator([mockContentType], mockComponents);
248+
expect(generatorWithComponents).toBeDefined();
249+
});
250+
251+
it("should handle strict mode with components", () => {
252+
const strictGenerator = new StrapiSchemaGenerator([mockContentType], mockComponents, true);
253+
expect(strictGenerator).toBeDefined();
254+
});
255+
});
64256
});

0 commit comments

Comments
 (0)