@comet/agent-features 9.0.0-beta.5
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/LICENSE +24 -0
- package/package.json +19 -0
- package/rules/coding-guidelines/api-nestjs.instructions.md +107 -0
- package/rules/coding-guidelines/cdn.instructions.md +24 -0
- package/rules/coding-guidelines/general.instructions.md +30 -0
- package/rules/coding-guidelines/git.instructions.md +37 -0
- package/rules/coding-guidelines/kubernetes.instructions.md +59 -0
- package/rules/coding-guidelines/libraries.instructions.md +34 -0
- package/rules/coding-guidelines/naming.instructions.md +39 -0
- package/rules/coding-guidelines/postgresql.instructions.md +40 -0
- package/rules/coding-guidelines/react.instructions.md +102 -0
- package/rules/coding-guidelines/security.instructions.md +44 -0
- package/rules/coding-guidelines/styling.instructions.md +50 -0
- package/rules/coding-guidelines/typescript.instructions.md +50 -0
- package/skills/.gitkeep +0 -0
- package/skills/comet-block/SKILL.md +246 -0
- package/skills/comet-block/references/admin-patterns.md +192 -0
- package/skills/comet-block/references/api-patterns.md +183 -0
- package/skills/comet-block/references/block-loader.md +368 -0
- package/skills/comet-block/references/block-types.md +210 -0
- package/skills/comet-block/references/custom-block-field.md +266 -0
- package/skills/comet-block/references/fixtures.md +436 -0
- package/skills/comet-block/references/image.md +341 -0
- package/skills/comet-block/references/migration.md +597 -0
- package/skills/comet-block/references/registration.md +167 -0
- package/skills/comet-block/references/response-summary.md +102 -0
- package/skills/comet-block/references/rich-text.md +309 -0
- package/skills/comet-block/references/select.md +176 -0
- package/skills/comet-block/references/site-patterns.md +202 -0
- package/skills/comet-mail-react/SKILL.md +541 -0
- package/skills/comet-mail-react/references/components-and-theme.md +441 -0
- package/skills/comet-mail-react/references/layout-patterns.md +315 -0
- package/skills/comet-mail-react/references/styling-and-customization.md +306 -0
- package/skills/comet-minor-update/SKILL.md +191 -0
- package/skills/dev-pm/SKILL.md +100 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# Block Fixture Rules
|
|
2
|
+
|
|
3
|
+
Detailed rules for creating and maintaining block fixture services that generate realistic seed data for Comet blocks. Load this file when creating a new block, editing an existing block, or managing fixture services.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Block fixtures are NestJS `@Injectable()` services that generate realistic seed data for development databases using `@faker-js/faker`. Each block fixture service maps 1:1 to an API block and implements a `generateBlockInput()` method that returns a populated block input shape.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## When to Create Fixtures
|
|
14
|
+
|
|
15
|
+
- Create a fixture service whenever a new block is created.
|
|
16
|
+
- Fixtures populate development databases with realistic test data so developers and editors can see how content looks without manually entering data.
|
|
17
|
+
- Each block fixture service corresponds to exactly one API block.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## File Structure and Naming
|
|
22
|
+
|
|
23
|
+
- **File:** `{block-name}-block-fixture.service.ts` (kebab-case)
|
|
24
|
+
- **Class:** `{BlockName}BlockFixtureService`
|
|
25
|
+
- **Location:** Discover the existing fixtures directory structure in the project. Fixtures typically live in `api/src/db/fixtures/generators/blocks/{category}/`.
|
|
26
|
+
- **Categories** typically mirror block types (e.g., `layout`, `media`, `navigation`, `teaser`, `text-and-content`). Place the new fixture in the category that best matches the block's purpose.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Core Type and Interface
|
|
31
|
+
|
|
32
|
+
Projects define a shared `BlockFixture` type that every fixture service must satisfy:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { type Block, type ExtractBlockInputFactoryProps } from "@comet/cms-api";
|
|
36
|
+
|
|
37
|
+
export type BlockFixture = {
|
|
38
|
+
generateBlockInput: () => Promise<ExtractBlockInputFactoryProps<Block>>;
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Every fixture service must implement `generateBlockInput()` returning `Promise<ExtractBlockInputFactoryProps<typeof TheBlock>>`. The service is decorated with `@Injectable()` and composes child fixture services via constructor injection.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Fixture Patterns by Block Type
|
|
47
|
+
|
|
48
|
+
### 1. Composite Block Fixture
|
|
49
|
+
|
|
50
|
+
For blocks created with `createBlock()`. Inject child fixture services via the constructor, generate each field with faker, and delegate child blocks to their fixture services.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { faker } from "@faker-js/faker";
|
|
54
|
+
import { Injectable } from "@nestjs/common";
|
|
55
|
+
import { DamImageBlock, type ExtractBlockInputFactoryProps } from "@comet/cms-api";
|
|
56
|
+
import { MyItemBlock } from "@src/documents/pages/blocks/my-item.block";
|
|
57
|
+
import { type BlockFixture } from "../block-fixture.type";
|
|
58
|
+
import { DamImageBlockFixtureService } from "../media/dam-image-block-fixture.service";
|
|
59
|
+
import { RichTextBlockFixtureService } from "../text-and-content/rich-text-block-fixture.service";
|
|
60
|
+
|
|
61
|
+
// Import the enum directly from the block file
|
|
62
|
+
import { Variant } from "@src/documents/pages/blocks/my-item.block";
|
|
63
|
+
|
|
64
|
+
@Injectable()
|
|
65
|
+
export class MyItemBlockFixtureService implements BlockFixture {
|
|
66
|
+
constructor(
|
|
67
|
+
private readonly damImageBlockFixtureService: DamImageBlockFixtureService,
|
|
68
|
+
private readonly richTextBlockFixtureService: RichTextBlockFixtureService,
|
|
69
|
+
) {}
|
|
70
|
+
|
|
71
|
+
async generateBlockInput(): Promise<ExtractBlockInputFactoryProps<typeof MyItemBlock>> {
|
|
72
|
+
return {
|
|
73
|
+
title: faker.lorem.words({ min: 3, max: 9 }),
|
|
74
|
+
variant: faker.helpers.arrayElement(Object.values(Variant)),
|
|
75
|
+
image: await this.damImageBlockFixtureService.generateBlockInput(),
|
|
76
|
+
description: await this.richTextBlockFixtureService.generateBlockInput(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. List Block Fixture
|
|
83
|
+
|
|
84
|
+
For blocks created with `createListBlock()`. Accept optional `min`/`max` parameters to control the number of generated items. Each item has a `key`, `visible` flag, and `props` delegated to the item fixture service.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { faker } from "@faker-js/faker";
|
|
88
|
+
import { Injectable } from "@nestjs/common";
|
|
89
|
+
import { type ExtractBlockInputFactoryProps } from "@comet/cms-api";
|
|
90
|
+
import { MyListBlock } from "@src/documents/pages/blocks/my-list.block";
|
|
91
|
+
import { type BlockFixture } from "../block-fixture.type";
|
|
92
|
+
import { MyItemBlockFixtureService } from "./my-item-block-fixture.service";
|
|
93
|
+
|
|
94
|
+
@Injectable()
|
|
95
|
+
export class MyListBlockFixtureService implements BlockFixture {
|
|
96
|
+
constructor(private readonly myItemBlockFixtureService: MyItemBlockFixtureService) {}
|
|
97
|
+
|
|
98
|
+
async generateBlockInput(settings: { min?: number; max?: number } = {}): Promise<ExtractBlockInputFactoryProps<typeof MyListBlock>> {
|
|
99
|
+
const { min = 2, max = 6 } = settings;
|
|
100
|
+
const itemCount = faker.number.int({ min, max });
|
|
101
|
+
|
|
102
|
+
const blocks = [];
|
|
103
|
+
for (let i = 0; i < itemCount; i++) {
|
|
104
|
+
blocks.push({
|
|
105
|
+
key: faker.string.uuid(),
|
|
106
|
+
visible: true,
|
|
107
|
+
props: await this.myItemBlockFixtureService.generateBlockInput(),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { blocks };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 3. Blocks Block Fixture
|
|
117
|
+
|
|
118
|
+
For blocks created with `createBlocksBlock()`. Define a `Record<string, BlockFixture>` mapping each supported block type key to its fixture service. Iterate over all types and generate entries.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { faker } from "@faker-js/faker";
|
|
122
|
+
import { Injectable } from "@nestjs/common";
|
|
123
|
+
import { type ExtractBlockInputFactoryProps } from "@comet/cms-api";
|
|
124
|
+
import { MyContentBlock } from "@src/documents/pages/blocks/my-content.block";
|
|
125
|
+
import { type BlockFixture } from "../block-fixture.type";
|
|
126
|
+
import { RichTextBlockFixtureService } from "../text-and-content/rich-text-block-fixture.service";
|
|
127
|
+
import { HeadingBlockFixtureService } from "../text-and-content/heading-block-fixture.service";
|
|
128
|
+
import { SpaceBlockFixtureService } from "../layout/space-block-fixture.service";
|
|
129
|
+
|
|
130
|
+
@Injectable()
|
|
131
|
+
export class MyContentBlockFixtureService implements BlockFixture {
|
|
132
|
+
private readonly blockFixtures: Record<string, BlockFixture>;
|
|
133
|
+
|
|
134
|
+
constructor(
|
|
135
|
+
private readonly richTextBlockFixtureService: RichTextBlockFixtureService,
|
|
136
|
+
private readonly headingBlockFixtureService: HeadingBlockFixtureService,
|
|
137
|
+
private readonly spaceBlockFixtureService: SpaceBlockFixtureService,
|
|
138
|
+
) {
|
|
139
|
+
this.blockFixtures = {
|
|
140
|
+
richText: this.richTextBlockFixtureService,
|
|
141
|
+
heading: this.headingBlockFixtureService,
|
|
142
|
+
space: this.spaceBlockFixtureService,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async generateBlockInput(): Promise<ExtractBlockInputFactoryProps<typeof MyContentBlock>> {
|
|
147
|
+
const blocks = [];
|
|
148
|
+
|
|
149
|
+
for (const [type, fixtureService] of Object.entries(this.blockFixtures)) {
|
|
150
|
+
blocks.push({
|
|
151
|
+
key: faker.string.uuid(),
|
|
152
|
+
visible: true,
|
|
153
|
+
type,
|
|
154
|
+
props: await fixtureService.generateBlockInput(),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { blocks };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 4. One-Of / Union Block Fixture
|
|
164
|
+
|
|
165
|
+
For blocks created with `createOneOfBlock()` or `createLinkBlock()`. Generate all possible types in the `attachedBlocks` array and randomly select one as `activeType`.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { faker } from "@faker-js/faker";
|
|
169
|
+
import { Injectable } from "@nestjs/common";
|
|
170
|
+
import { type ExtractBlockInputFactoryProps } from "@comet/cms-api";
|
|
171
|
+
import { MyOneOfBlock } from "@src/documents/pages/blocks/my-one-of.block";
|
|
172
|
+
import { type BlockFixture } from "../block-fixture.type";
|
|
173
|
+
import { DamImageBlockFixtureService } from "../media/dam-image-block-fixture.service";
|
|
174
|
+
import { DamVideoBlockFixtureService } from "../media/dam-video-block-fixture.service";
|
|
175
|
+
|
|
176
|
+
@Injectable()
|
|
177
|
+
export class MyOneOfBlockFixtureService implements BlockFixture {
|
|
178
|
+
private readonly blockFixtures: Record<string, BlockFixture>;
|
|
179
|
+
|
|
180
|
+
constructor(
|
|
181
|
+
private readonly damImageBlockFixtureService: DamImageBlockFixtureService,
|
|
182
|
+
private readonly damVideoBlockFixtureService: DamVideoBlockFixtureService,
|
|
183
|
+
) {
|
|
184
|
+
this.blockFixtures = {
|
|
185
|
+
image: this.damImageBlockFixtureService,
|
|
186
|
+
damVideo: this.damVideoBlockFixtureService,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async generateBlockInput(): Promise<ExtractBlockInputFactoryProps<typeof MyOneOfBlock>> {
|
|
191
|
+
const attachedBlocks = [];
|
|
192
|
+
|
|
193
|
+
for (const [type, fixtureService] of Object.entries(this.blockFixtures)) {
|
|
194
|
+
attachedBlocks.push({
|
|
195
|
+
type,
|
|
196
|
+
props: await fixtureService.generateBlockInput(),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const activeType = faker.helpers.arrayElement(Object.keys(this.blockFixtures));
|
|
201
|
+
|
|
202
|
+
return { attachedBlocks, activeType };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 5. Simple / Empty Block Fixture
|
|
208
|
+
|
|
209
|
+
Blocks with no data fields return an empty object.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { Injectable } from "@nestjs/common";
|
|
213
|
+
import { type ExtractBlockInputFactoryProps } from "@comet/cms-api";
|
|
214
|
+
import { MySpacerBlock } from "@src/documents/pages/blocks/my-spacer.block";
|
|
215
|
+
import { type BlockFixture } from "../block-fixture.type";
|
|
216
|
+
|
|
217
|
+
@Injectable()
|
|
218
|
+
export class MySpacerBlockFixtureService implements BlockFixture {
|
|
219
|
+
async generateBlockInput(): Promise<ExtractBlockInputFactoryProps<typeof MySpacerBlock>> {
|
|
220
|
+
return {};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Faker.js Guidelines for Realistic Values
|
|
228
|
+
|
|
229
|
+
Match the faker method to the field's semantic purpose. A headline should be a few words, not a paragraph. A link label should be 1–3 words. List item counts should be small.
|
|
230
|
+
|
|
231
|
+
| Field Semantic | Faker Method | Notes |
|
|
232
|
+
| --------------------------- | --------------------------------------------------- | --------------------------------------------------------------- |
|
|
233
|
+
| Title / headline | `faker.lorem.words({ min: 3, max: 9 })` | Short phrase, not a sentence |
|
|
234
|
+
| Eyebrow / label | `faker.lorem.words({ min: 2, max: 5 })` | Compact label text |
|
|
235
|
+
| Link text / button text | `faker.lorem.words({ min: 1, max: 3 })` | Very short |
|
|
236
|
+
| Sentence (fact, caption) | `faker.lorem.sentence()` | Single sentence |
|
|
237
|
+
| Paragraph / body text | `faker.lorem.paragraph()` | Inside RichText Draft content blocks |
|
|
238
|
+
| Anchor name | `faker.word.words(3)` | Short identifier |
|
|
239
|
+
| Enum | `faker.helpers.arrayElement(Object.values(MyEnum))` | Import the enum from the block file |
|
|
240
|
+
| Boolean | `faker.datatype.boolean()` | |
|
|
241
|
+
| Number (percentage/overlay) | `faker.number.int({ min: 50, max: 90 })` | Constrain to a realistic range |
|
|
242
|
+
| Number (list item count) | `faker.number.int({ min: 2, max: 6 })` | Small, realistic set |
|
|
243
|
+
| Block key (UUID) | `faker.string.uuid()` | Used for `key` in list/blocks entries |
|
|
244
|
+
| URL | `faker.internet.url()` | Or use `faker.helpers.arrayElement([...])` with predefined URLs |
|
|
245
|
+
| SEO title | `faker.word.words(2)` | |
|
|
246
|
+
| SEO meta description | `faker.word.words(20)` | |
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## RichText (Draft.js) Fixture Pattern
|
|
251
|
+
|
|
252
|
+
RichText blocks use Draft.js structure. Generate the content inline using `draftContent` with `blocks` and `entityMap`.
|
|
253
|
+
|
|
254
|
+
> **Important:** The `type` value in each Draft.js block must match a block type actually defined in the project's `RichTextBlock`. **Always check the project's Admin-side `RichTextBlock` configuration** (its `blocktypeMap` and `standardBlockType`) before writing fixture data. The examples below use `"paragraph-standard"` and `"header-one"` as illustrations — these types may not exist in the current project. Even `"unstyled"` (the Draft.js default) may be absent if the project overrides `standardBlockType` with a custom type. Use whichever type the project actually defines.
|
|
255
|
+
|
|
256
|
+
### Paragraph Content
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
// "paragraph-standard" is an example — use the actual paragraph block type from the project's RichTextBlock definition
|
|
260
|
+
const generateParagraphRichText = () => ({
|
|
261
|
+
draftContent: {
|
|
262
|
+
blocks: [
|
|
263
|
+
{
|
|
264
|
+
key: faker.string.uuid(),
|
|
265
|
+
text: faker.lorem.paragraph(),
|
|
266
|
+
type: "paragraph-standard",
|
|
267
|
+
depth: 0,
|
|
268
|
+
inlineStyleRanges: [],
|
|
269
|
+
entityRanges: [],
|
|
270
|
+
data: {},
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
entityMap: {},
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Heading Content
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
// "header-one" is an example — verify that heading block types exist in the project's RichTextBlock definition
|
|
282
|
+
const generateHeadingRichText = () => ({
|
|
283
|
+
draftContent: {
|
|
284
|
+
blocks: [
|
|
285
|
+
{
|
|
286
|
+
key: faker.string.uuid(),
|
|
287
|
+
text: faker.lorem.words({ min: 3, max: 9 }),
|
|
288
|
+
type: "header-one",
|
|
289
|
+
depth: 0,
|
|
290
|
+
inlineStyleRanges: [],
|
|
291
|
+
entityRanges: [],
|
|
292
|
+
data: {},
|
|
293
|
+
},
|
|
294
|
+
],
|
|
295
|
+
entityMap: {},
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Notes
|
|
301
|
+
|
|
302
|
+
- **Always check the project's `RichTextBlock` configuration** to determine which block types are valid. The `type` field must exactly match a type that the block defines — either through `blocktypeMap` or as a standard Draft.js type that is explicitly supported.
|
|
303
|
+
- `"paragraph-standard"` and `"paragraph-small"` are project-defined custom types and will not exist in every project.
|
|
304
|
+
- `"header-one"` through `"header-six"` are standard Draft.js types but only valid if the project's RichTextBlock actually includes them in `supports`.
|
|
305
|
+
- `"unstyled"` is the Draft.js default but may be suppressed if the project sets a custom `standardBlockType` — in that case it is not a valid choice for fixture data either.
|
|
306
|
+
- Always include `key`, `depth: 0`, `inlineStyleRanges: []`, `entityRanges: []`, and `data: {}`.
|
|
307
|
+
- Wrap the content in `{ draftContent: { blocks: [...], entityMap: {} } }`.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Registration and Parent Fixture Wiring
|
|
312
|
+
|
|
313
|
+
After creating a fixture service, perform these steps:
|
|
314
|
+
|
|
315
|
+
### 1. Register in the fixtures module
|
|
316
|
+
|
|
317
|
+
Add the new fixture service as a provider in the project's `fixtures.module.ts`:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
// api/src/db/fixtures/fixtures.module.ts
|
|
321
|
+
import { MyItemBlockFixtureService } from "./generators/blocks/teaser/my-item-block-fixture.service";
|
|
322
|
+
|
|
323
|
+
@Module({
|
|
324
|
+
providers: [
|
|
325
|
+
// ... existing providers
|
|
326
|
+
MyItemBlockFixtureService,
|
|
327
|
+
],
|
|
328
|
+
})
|
|
329
|
+
export class FixturesModule {}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### 2. Wire into the parent block's fixture
|
|
333
|
+
|
|
334
|
+
The new block is always registered in a parent block (typically a blocks-block like a page content block). Find the parent block's fixture service and add the new fixture there:
|
|
335
|
+
|
|
336
|
+
1. Inject the new fixture service into the parent fixture's constructor.
|
|
337
|
+
2. Add a new entry in the parent fixture's `blockFixtures` record, mapping the block's type key (the same camelCase key used in `supportedBlocks`) to the new fixture service.
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
// In the parent blocks-block fixture service
|
|
341
|
+
constructor(
|
|
342
|
+
// ... existing injections
|
|
343
|
+
private readonly myItemBlockFixtureService: MyItemBlockFixtureService,
|
|
344
|
+
) {
|
|
345
|
+
this.blockFixtures = {
|
|
346
|
+
// ... existing entries
|
|
347
|
+
myItem: this.myItemBlockFixtureService,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### 3. If the parent has no fixture
|
|
353
|
+
|
|
354
|
+
Check whether the parent blocks-block already has a fixture service. If it does not, ask the user whether a fixture service should be created for the parent block as well, or whether fixtures should be skipped entirely for this block.
|
|
355
|
+
|
|
356
|
+
### 4. Composite block parent
|
|
357
|
+
|
|
358
|
+
If the new block is a child of another composite block (not a blocks-block), inject the new fixture into that parent fixture's constructor and call its `generateBlockInput()` in the parent's own `generateBlockInput()` method.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Editing Existing Block Fixtures
|
|
363
|
+
|
|
364
|
+
Whenever an existing block is modified, its fixture must be updated to match.
|
|
365
|
+
|
|
366
|
+
| Change Type | Fixture Action |
|
|
367
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
368
|
+
| **Field added** | Add the new field to `generateBlockInput()` with an appropriate faker call. |
|
|
369
|
+
| **Field removed** | Remove the field from `generateBlockInput()`. |
|
|
370
|
+
| **Field type changed** | Update the faker call or child fixture delegation to match the new type. |
|
|
371
|
+
| **Enum values changed** | Update the enum import. No other fixture change is usually needed since `faker.helpers.arrayElement(Object.values(...))` picks from all values automatically. |
|
|
372
|
+
| **Block renamed** | Rename the fixture service class, file, and all references (imports, constructor injections, module registration, parent fixture wiring). |
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Deleting a Block's Fixtures
|
|
377
|
+
|
|
378
|
+
When a block is deleted:
|
|
379
|
+
|
|
380
|
+
1. Delete the fixture service file.
|
|
381
|
+
2. Remove it from `fixtures.module.ts` providers.
|
|
382
|
+
3. Remove it from any parent fixture service (constructor injection, `blockFixtures` record entry, and import).
|
|
383
|
+
4. If the deleted block had child fixture services that are no longer used by any other fixture, delete those too.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Conditional Logic Patterns
|
|
388
|
+
|
|
389
|
+
Some blocks have fields that depend on other field values. Reflect this in fixtures.
|
|
390
|
+
|
|
391
|
+
**Boolean-dependent fields:**
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
const autoplay = faker.datatype.boolean();
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
autoplay,
|
|
398
|
+
showControls: !autoplay,
|
|
399
|
+
// ...
|
|
400
|
+
};
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Enum-dependent optional fields:**
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
const variant = faker.helpers.arrayElement(Object.values(Variant));
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
variant,
|
|
410
|
+
subtitle: variant === "expanded" ? faker.lorem.words({ min: 3, max: 9 }) : undefined,
|
|
411
|
+
// ...
|
|
412
|
+
};
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
**Optional settings parameter for controlling generation behavior:**
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
async generateBlockInput(
|
|
419
|
+
settings: { min?: number; max?: number; includeOptional?: boolean } = {},
|
|
420
|
+
): Promise<ExtractBlockInputFactoryProps<typeof MyBlock>> {
|
|
421
|
+
const { min = 2, max = 6, includeOptional = true } = settings;
|
|
422
|
+
// ...
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Cross-references
|
|
429
|
+
|
|
430
|
+
| Topic | File |
|
|
431
|
+
| ---------------------------------------------------- | ---------------------------------- |
|
|
432
|
+
| Block creation workflow and registration | [SKILL.md](../SKILL.md) |
|
|
433
|
+
| API block patterns, decorators, field rules | [api-patterns.md](api-patterns.md) |
|
|
434
|
+
| Enum/select patterns and enum imports | [select.md](select.md) |
|
|
435
|
+
| RichText block structure (relevant to Draft.js data) | [rich-text.md](rich-text.md) |
|
|
436
|
+
| Image block types and selection | [image.md](image.md) |
|