eventmodeler 0.6.0 → 0.6.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.
Files changed (73) hide show
  1. package/dist/index.js +7133 -34
  2. package/package.json +5 -4
  3. package/dist/api/client-config.js +0 -10
  4. package/dist/api/generated/client/client.gen.js +0 -235
  5. package/dist/api/generated/client/index.js +0 -6
  6. package/dist/api/generated/client/types.gen.js +0 -2
  7. package/dist/api/generated/client/utils.gen.js +0 -228
  8. package/dist/api/generated/client.gen.js +0 -4
  9. package/dist/api/generated/core/auth.gen.js +0 -14
  10. package/dist/api/generated/core/bodySerializer.gen.js +0 -57
  11. package/dist/api/generated/core/params.gen.js +0 -100
  12. package/dist/api/generated/core/pathSerializer.gen.js +0 -106
  13. package/dist/api/generated/core/queryKeySerializer.gen.js +0 -92
  14. package/dist/api/generated/core/serverSentEvents.gen.js +0 -133
  15. package/dist/api/generated/core/types.gen.js +0 -2
  16. package/dist/api/generated/core/utils.gen.js +0 -87
  17. package/dist/api/generated/index.js +0 -2
  18. package/dist/api/generated/sdk.gen.js +0 -4222
  19. package/dist/api/generated/types.gen.js +0 -2
  20. package/dist/api/generated/zod.gen.js +0 -7217
  21. package/dist/commands/add.js +0 -315
  22. package/dist/commands/auth.js +0 -14
  23. package/dist/commands/create.js +0 -192
  24. package/dist/commands/design.js +0 -108
  25. package/dist/commands/guide.js +0 -15
  26. package/dist/commands/init.js +0 -21
  27. package/dist/commands/list-schemas.js +0 -177
  28. package/dist/commands/list.js +0 -39
  29. package/dist/commands/loop.js +0 -101
  30. package/dist/commands/map.js +0 -40
  31. package/dist/commands/mark.js +0 -27
  32. package/dist/commands/move.js +0 -35
  33. package/dist/commands/remove.js +0 -170
  34. package/dist/commands/rename.js +0 -53
  35. package/dist/commands/resize.js +0 -30
  36. package/dist/commands/search.js +0 -14
  37. package/dist/commands/set.js +0 -199
  38. package/dist/commands/show-schemas.js +0 -259
  39. package/dist/commands/show.js +0 -56
  40. package/dist/commands/summary.js +0 -13
  41. package/dist/commands/update.js +0 -240
  42. package/dist/lib/auth.js +0 -331
  43. package/dist/lib/config.js +0 -80
  44. package/dist/lib/excalidraw-schema.js +0 -66
  45. package/dist/lib/globals.js +0 -8
  46. package/dist/lib/model.js +0 -11
  47. package/dist/lib/project-config.js +0 -103
  48. package/dist/lib/resolve.js +0 -59
  49. package/dist/lib/scenario.js +0 -15
  50. package/dist/slices/add-scenario/index.js +0 -103
  51. package/dist/slices/guide/guides/codegen.js +0 -339
  52. package/dist/slices/guide/guides/connect-slices.js +0 -202
  53. package/dist/slices/guide/guides/create-slices.js +0 -273
  54. package/dist/slices/guide/guides/explore.js +0 -238
  55. package/dist/slices/guide/guides/information-flow.js +0 -304
  56. package/dist/slices/guide/guides/scenarios.js +0 -214
  57. package/dist/slices/guide/index.js +0 -40
  58. package/dist/slices/help/index.js +0 -96
  59. package/dist/slices/help/topics/build-codegen.js +0 -109
  60. package/dist/slices/help/topics/build-slice.js +0 -147
  61. package/dist/slices/help/topics/check-completeness.js +0 -57
  62. package/dist/slices/help/topics/connect-slices.js +0 -99
  63. package/dist/slices/help/topics/explore-model.js +0 -112
  64. package/dist/slices/help/topics/json-reference.js +0 -188
  65. package/dist/slices/help/topics/linked-copies.js +0 -89
  66. package/dist/slices/help/topics/manipulate-canvas.js +0 -150
  67. package/dist/slices/help/topics/write-scenarios.js +0 -162
  68. package/dist/slices/init/index.js +0 -86
  69. package/dist/slices/init/loop.js +0 -60
  70. package/dist/slices/login/index.js +0 -20
  71. package/dist/slices/logout/index.js +0 -14
  72. package/dist/slices/open-app/index.js +0 -36
  73. package/dist/slices/whoami/index.js +0 -19
@@ -1,304 +0,0 @@
1
- export const meta = {
2
- name: 'information-flow',
3
- description: 'Design fields, map data between elements, update properties, and check completeness',
4
- };
5
- export const content = `
6
- # Information Flow: Fields, Mappings, and Completeness
7
-
8
- This guide covers the full lifecycle of information in an event model: designing fields, adding them to elements, mapping data between connected elements, updating field properties, and verifying completeness.
9
-
10
- ---
11
-
12
- ## Designing Read Models
13
-
14
- Read models are projections of event data - views that serve specific screens or use cases. Every field in a read model should trace back to event fields.
15
-
16
- ### Understand the Context
17
- \`\`\`bash
18
- # Look at the slice containing the read model
19
- eventmodeler show slice "<slice-name>"
20
-
21
- # Check current completeness - what's missing?
22
- eventmodeler show completeness "<read-model-name>"
23
-
24
- # See what events feed into this read model
25
- eventmodeler list events
26
- \`\`\`
27
-
28
- ### Design the Fields
29
- Based on the use case, identify what fields are needed:
30
- - **Identity fields** - IDs to identify the entity
31
- - **Display fields** - What the user sees
32
- - **Status fields** - Current state
33
- - **Computed fields** - Aggregations, counts, derived values
34
- - **Timestamp fields** - When things happened
35
-
36
- ### Propose Before Adding
37
- \`\`\`
38
- I suggest these fields for the OrderHistory read model:
39
- - orderId (UUID) - identifies the order
40
- - customerId (UUID) - who placed it
41
- - status (String) - current status: pending, shipped, delivered, cancelled
42
- - total (Decimal) - order total
43
- - placedAt (DateTime) - when it was placed
44
- - lastUpdatedAt (DateTime) - when status last changed
45
-
46
- Does this look right?
47
- \`\`\`
48
-
49
- ## Adding Fields
50
-
51
- Field types: \`UUID\`, \`String\`, \`Int\`, \`Long\`, \`Double\`, \`Decimal\`, \`Boolean\`, \`Date\`, \`DateTime\`, \`Custom\`
52
-
53
- \`\`\`bash
54
- # Add a simple field
55
- eventmodeler add field "OrderSummary" '{"name": "orderId", "type": "UUID"}'
56
-
57
- # Add an optional field
58
- eventmodeler add field "OrderSummary" '{"name": "cancelledAt", "type": "DateTime", "isOptional": true}'
59
-
60
- # Add a list field
61
- eventmodeler add field "OrderSummary" '{"name": "itemIds", "type": "UUID", "isList": true}'
62
-
63
- # Add a complex/nested field
64
- eventmodeler add field "OrderSummary" '{"name": "shippingAddress", "type": "Custom", "subfields": [
65
- {"name": "street", "type": "String"},
66
- {"name": "city", "type": "String"},
67
- {"name": "postalCode", "type": "String"}
68
- ]}'
69
- \`\`\`
70
-
71
- **CRITICAL: Custom fields MUST contain subfields.** A Custom field without subfields is invalid.
72
-
73
- ### Lists and Custom Types
74
-
75
- **List of custom objects** - combine \`"type": "Custom"\` with \`"isList": true\`:
76
- \`\`\`bash
77
- eventmodeler add field "OrderSummary" '{"name": "lineItems", "type": "Custom", "isList": true, "subfields": [
78
- {"name": "productId", "type": "UUID"},
79
- {"name": "productName", "type": "String"},
80
- {"name": "quantity", "type": "Int"},
81
- {"name": "unitPrice", "type": "Decimal"}
82
- ]}'
83
- \`\`\`
84
-
85
- **Nested custom types** - subfields can themselves be Custom:
86
- \`\`\`bash
87
- eventmodeler add field "OrderSummary" '{"name": "customer", "type": "Custom", "subfields": [
88
- {"name": "customerId", "type": "UUID"},
89
- {"name": "name", "type": "String"},
90
- {"name": "billingAddress", "type": "Custom", "subfields": [
91
- {"name": "street", "type": "String"},
92
- {"name": "city", "type": "String"},
93
- {"name": "country", "type": "String"}
94
- ]}
95
- ]}'
96
- \`\`\`
97
-
98
- ---
99
-
100
- ## Mapping Fields on Flows
101
-
102
- Field mappings define how data flows from source elements to target elements. When you connect an Event to a ReadModel with a flow, the field mappings specify which event fields populate which read model fields.
103
-
104
- ### Command Syntax
105
-
106
- \`\`\`bash
107
- eventmodeler map fields --from "<source>" --to "<target>" '[{"from": "sourceField", "to": "targetField"}]'
108
- \`\`\`
109
-
110
- Or with multiple mappings:
111
-
112
- \`\`\`bash
113
- eventmodeler map fields --from "OrderPlaced" --to "OrderSummary" '[
114
- {"from": "orderId", "to": "orderId"},
115
- {"from": "customerId", "to": "customerId"},
116
- {"from": "totalAmount", "to": "total"}
117
- ]'
118
- \`\`\`
119
-
120
- ### Source/Target Formats
121
-
122
- The \`--from\` and \`--to\` arguments accept:
123
-
124
- 1. **Element name** (most common): \`"OrderPlaced"\`
125
- 2. **Element ID prefix** (for duplicates): \`"id:abc12345"\`
126
-
127
- ### Workflow
128
-
129
- 1. **Find flows needing mappings**: \`eventmodeler show model-completeness\`
130
- 2. **See source fields**: \`eventmodeler show event "OrderPlaced"\`
131
- 3. **See target fields**: \`eventmodeler show completeness "OrderSummary"\`
132
- 4. **Create mappings**: \`eventmodeler map fields --from "OrderPlaced" --to "OrderSummary" '[...]'\`
133
- 5. **Verify**: \`eventmodeler show completeness "OrderSummary"\`
134
-
135
- ### Mapping Nested Fields
136
-
137
- For Custom (nested) field types, use dot notation:
138
-
139
- \`\`\`bash
140
- eventmodeler map fields --from "OrderPlaced" --to "OrderSummary" '[
141
- {"from": "shippingAddress.street", "to": "deliveryAddress.street"},
142
- {"from": "shippingAddress.city", "to": "deliveryAddress.city"},
143
- {"from": "shippingAddress.postalCode", "to": "deliveryAddress.zip"}
144
- ]'
145
- \`\`\`
146
-
147
- ### Multiple Flows to Same Target
148
-
149
- A read model often receives data from multiple events. Map each flow separately:
150
-
151
- \`\`\`bash
152
- # Initial data from OrderPlaced
153
- eventmodeler map fields --from "OrderPlaced" --to "OrderSummary" '[
154
- {"from": "orderId", "to": "orderId"},
155
- {"from": "customerId", "to": "customerId"},
156
- {"from": "totalAmount", "to": "total"}
157
- ]'
158
-
159
- # Status updates from OrderShipped
160
- eventmodeler map fields --from "OrderShipped" --to "OrderSummary" '[
161
- {"from": "shippedAt", "to": "shippedDate"},
162
- {"from": "trackingNumber", "to": "trackingNumber"}
163
- ]'
164
- \`\`\`
165
-
166
- ### Updating Existing Mappings
167
-
168
- Running \`map fields\` again **merges** with existing mappings:
169
- - New mappings are added
170
- - If a target field already has a mapping, it's replaced with the new source
171
-
172
- ### Common Mapping Patterns
173
-
174
- | Pattern | Example |
175
- |---------|---------|
176
- | Identity | \`{"from": "orderId", "to": "orderId"}\` |
177
- | Rename | \`{"from": "totalAmount", "to": "total"}\` |
178
- | Nested to flat | \`{"from": "customer.id", "to": "customerId"}\` |
179
- | Flat to nested | \`{"from": "street", "to": "address.street"}\` |
180
-
181
- ---
182
-
183
- ## Updating Field Properties
184
-
185
- Use \`update field\` to modify field attributes without changing the field's name or structure.
186
-
187
- ### Command Syntax
188
-
189
- \`\`\`bash
190
- eventmodeler update field <element-name> --field "<field-name>" [options]
191
- \`\`\`
192
-
193
- ### Available Options
194
-
195
- | Option | Values | Description |
196
- |--------|--------|-------------|
197
- | \`--optional\` | \`true\`/\`false\` | Mark field as not required for completeness |
198
- | \`--generated\` | \`true\`/\`false\` | Mark field as system-generated (not from user input) |
199
- | \`--user-input\` | \`true\`/\`false\` | Mark field as user-provided (screens only) |
200
- | \`--type\` | Field type | Change the field's data type |
201
-
202
- ### Examples
203
-
204
- \`\`\`bash
205
- # Mark a field as optional
206
- eventmodeler update field "OrderPlaced" --field "promoCode" --optional true
207
-
208
- # Mark a field as system-generated
209
- eventmodeler update field "OrderPlaced" --field "orderId" --generated true
210
-
211
- # Mark screen fields as user input
212
- eventmodeler update field "Checkout" --field "email" --user-input true
213
-
214
- # Change a field's type
215
- eventmodeler update field "OrderSummary" --field "total" --type Decimal
216
-
217
- # Combine multiple updates
218
- eventmodeler update field "UserRegistered" --field "createdAt" --generated true --optional false
219
- \`\`\`
220
-
221
- ### Updating Nested Fields
222
-
223
- Use dot notation for fields inside Custom types:
224
-
225
- \`\`\`bash
226
- eventmodeler update field "OrderPlaced" --field "shippingAddress.postalCode" --optional true
227
- \`\`\`
228
-
229
- ### Field Property Meanings
230
-
231
- **isOptional**: Field may not always have a value. Completeness checks don't require this field to have a mapping source.
232
-
233
- **isGenerated**: Field is system-generated, not derived from other fields. Completeness checks don't require this field to have a mapping source. Use for: IDs, timestamps, sequence numbers, computed values.
234
-
235
- **isUserInput** (screens only): Field comes from user input on the screen. Identifies which screen fields are inputs vs. display-only.
236
-
237
- ---
238
-
239
- ## Removing Fields
240
-
241
- \`\`\`bash
242
- # Remove a field from an event
243
- eventmodeler remove field "OrderPlaced" --field "legacyId"
244
-
245
- # Remove a field from a read model
246
- eventmodeler remove field "OrderSummary" --field "deprecatedStatus"
247
-
248
- # Remove a nested field using dot notation
249
- eventmodeler remove field "OrderPlaced" --field "metadata.debugInfo"
250
- \`\`\`
251
-
252
- **Caution**: Removing a field may break existing field mappings. Check completeness first:
253
- \`\`\`bash
254
- eventmodeler show completeness "<element-name>"
255
- \`\`\`
256
-
257
- ---
258
-
259
- ## Checking Completeness
260
-
261
- ### Check a Specific Element
262
- \`\`\`bash
263
- eventmodeler show completeness "<name>"
264
- \`\`\`
265
- Shows incoming flows and which fields are satisfied vs unsatisfied.
266
-
267
- ### Check the Entire Model
268
- \`\`\`bash
269
- eventmodeler show model-completeness
270
- \`\`\`
271
- Project-wide view: complete count, incomplete count, and all incomplete flows with their unsatisfied fields.
272
-
273
- ### Check Aggregate ID Fields
274
- \`\`\`bash
275
- eventmodeler show aggregate-completeness "<aggregate-name>"
276
- \`\`\`
277
-
278
- ---
279
-
280
- ## Common Mistakes
281
-
282
- - **Creating empty Custom fields**: Custom fields MUST have subfields.
283
- - Wrong: \`{"name": "address", "type": "Custom"}\`
284
- - Right: \`{"name": "address", "type": "Custom", "subfields": [{"name": "street", "type": "String"}, ...]}\`
285
-
286
- - **Using "List" as a field type**: Use \`"isList": true\` with a valid type instead.
287
- - Wrong: \`{"name": "items", "type": "List"}\`
288
- - Right: \`{"name": "items", "type": "String", "isList": true}\`
289
-
290
- - **Using wrong attribute names**: Always use camelCase attributes.
291
- - Wrong: \`"optional": true\`, \`"generated": true\`, \`"list": true\`
292
- - Right: \`"isOptional": true\`, \`"isGenerated": true\`, \`"isList": true\`
293
-
294
- ## Best Practices
295
-
296
- 1. **Get approval before adding fields** - Propose the design, let the user confirm
297
- 2. **Consider all source events** - A read model may need data from multiple events
298
- 3. **Use appropriate types** - \`Decimal\` for money, \`DateTime\` for timestamps
299
- 4. **Mark optional fields** - Fields that may not always have values (e.g., \`cancelledAt\`)
300
- 5. **Mark generated fields early** - When creating slices, immediately mark IDs and timestamps as generated
301
- 6. **Map all fields at once** - More efficient than one mapping at a time
302
- 7. **Verify after mapping** - Run \`show completeness\` to confirm all fields are satisfied
303
- 8. **Check mappings before removing** - Removing a field can break existing mappings
304
- `;
@@ -1,214 +0,0 @@
1
- export const meta = {
2
- name: 'scenarios',
3
- description: 'Design Given-When-Then scenarios for slices: happy paths, errors, automations',
4
- };
5
- export const content = `
6
- # Designing Scenarios for Slices
7
-
8
- Scenarios define the behavior of a slice. There are two main scenario patterns:
9
-
10
- 1. **State-Change Scenarios** (for state-change slices): Given events → When command → Then events/error
11
- 2. **Automation Scenarios** (for automation slices): Given events → Then command (simpler Given-Then format)
12
-
13
- ## Your Workflow
14
-
15
- When helping design scenarios for a slice:
16
-
17
- ### 1. Gather Context
18
- \`\`\`bash
19
- # Look at the slice to understand its components
20
- eventmodeler show slice "<slice-name>"
21
-
22
- # See what chapter it belongs to and nearby slices for context
23
- eventmodeler list chapters
24
- eventmodeler show chapter "<chapter-name>"
25
-
26
- # List all events to understand what's available for Given clauses
27
- eventmodeler list events
28
- \`\`\`
29
-
30
- ### 2. Identify the Slice Type
31
-
32
- **State-Change Slice** (Screen → Command → Event):
33
- - User triggers a command
34
- - Command produces event(s)
35
- - Use: Given → When command → Then events/error
36
-
37
- **Automation Slice** (ReadModel → Processor → Command → Event):
38
- - Events trigger the processor to issue a command
39
- - Use simpler Given → Then format (no When)
40
- - Given: All events that lead to the trigger condition
41
- - Then: The command that should be dispatched (or noCommand)
42
-
43
- ### 3. Design Scenarios by Type
44
-
45
- ---
46
-
47
- ## State-Change Scenarios
48
-
49
- For slices where a user action triggers a command:
50
-
51
- **Happy Path** - The command succeeds under normal conditions
52
- - Given: Any required preconditions (existing events)
53
- - When: The command with valid input
54
- - Then: The expected event(s) with field values
55
-
56
- **Validation Errors** - Bad input is rejected
57
- - Given: (may be empty)
58
- - When: Command with invalid input
59
- - Then: Error with message
60
-
61
- **Business Rule Violations** - Valid input but rule prevents action
62
- - Given: Events that create a state where the action isn't allowed
63
- - When: The command
64
- - Then: Error explaining why
65
-
66
- ### State-Change Examples
67
-
68
- \`\`\`bash
69
- # Happy path - command succeeds
70
- eventmodeler add scenario --slice "<slice-name>" '{
71
- "name": "Successfully place order",
72
- "description": "A registered customer can place an order with valid items",
73
- "given": [
74
- {"event": "CustomerRegistered", "fieldValues": {"customerId": "cust-123"}}
75
- ],
76
- "when": {
77
- "command": "PlaceOrder",
78
- "commandFieldValues": {"customerId": "cust-123", "items": [{"productId": "prod-1", "quantity": 2}]}
79
- },
80
- "then": {
81
- "type": "events",
82
- "events": [
83
- {"event": "OrderPlaced", "fieldValues": {"orderId": "order-456", "customerId": "cust-123"}}
84
- ]
85
- }
86
- }'
87
- \`\`\`
88
-
89
- \`\`\`bash
90
- # Validation error
91
- eventmodeler add scenario --slice "<slice-name>" '{
92
- "name": "Cannot place empty order",
93
- "description": "Orders must contain at least one item - empty item lists are rejected",
94
- "when": {
95
- "command": "PlaceOrder",
96
- "commandFieldValues": {"customerId": "cust-123", "items": []}
97
- },
98
- "then": {
99
- "type": "error",
100
- "errorType": "ValidationError",
101
- "errorMessage": "Order must contain at least one item"
102
- }
103
- }'
104
- \`\`\`
105
-
106
- \`\`\`bash
107
- # Business rule violation
108
- eventmodeler add scenario --slice "Cancel Order" '{
109
- "name": "Cannot cancel shipped order",
110
- "description": "Once an order has been shipped, it can no longer be cancelled",
111
- "given": [
112
- {"event": "OrderPlaced", "fieldValues": {"orderId": "order-123"}},
113
- {"event": "OrderShipped", "fieldValues": {"orderId": "order-123", "shippedAt": "2024-01-15T10:00:00Z"}}
114
- ],
115
- "when": {
116
- "command": "CancelOrder",
117
- "commandFieldValues": {"orderId": "order-123"}
118
- },
119
- "then": {
120
- "type": "error",
121
- "errorType": "BusinessRuleViolation",
122
- "errorMessage": "Cannot cancel an order that has already shipped"
123
- }
124
- }'
125
- \`\`\`
126
-
127
- ---
128
-
129
- ## Automation Scenarios
130
-
131
- For slices where events trigger a processor to issue a command. Use the simpler **Given-Then** format:
132
-
133
- **Trigger Conditions Met** - Events cause processor to act
134
- - Given: All the events that have occurred (including the trigger events)
135
- - Then: The command the processor issues
136
-
137
- **Trigger Conditions Not Met** - Events don't cause action
138
- - Given: Events that don't meet the trigger condition
139
- - Then: noCommand (processor should not dispatch)
140
-
141
- ### Automation Examples
142
-
143
- \`\`\`bash
144
- # Payment received triggers shipment initiation
145
- eventmodeler add scenario --slice "Auto Ship Order" '{
146
- "name": "Payment triggers shipment",
147
- "description": "Given an order has been placed and payment received, the system automatically initiates shipment",
148
- "given": [
149
- {"event": "OrderPlaced", "fieldValues": {"orderId": "order-123", "customerId": "cust-456"}},
150
- {"event": "PaymentReceived", "fieldValues": {"orderId": "order-123", "amount": 99.99}}
151
- ],
152
- "then": {
153
- "type": "command",
154
- "command": "InitiateShipment",
155
- "commandFieldValues": {"orderId": "order-123", "warehouseId": "wh-001"}
156
- }
157
- }'
158
- \`\`\`
159
-
160
- \`\`\`bash
161
- # Negative case - conditions not met, no command dispatched
162
- eventmodeler add scenario --slice "Auto Ship Order" '{
163
- "name": "No shipment without payment",
164
- "description": "Given only an order placed (no payment), the system should not initiate shipment",
165
- "given": [
166
- {"event": "OrderPlaced", "fieldValues": {"orderId": "order-123", "customerId": "cust-456"}}
167
- ],
168
- "then": {
169
- "type": "noCommand"
170
- }
171
- }'
172
- \`\`\`
173
-
174
- ---
175
-
176
- ## Read Model Assertions
177
-
178
- For state-view slices, test that events project correctly to read models:
179
-
180
- \`\`\`bash
181
- eventmodeler add scenario --slice "<slice-name>" '{
182
- "name": "Order appears in summary",
183
- "description": "After placing an order, it should be visible in the order summary with pending status",
184
- "given": [
185
- {"event": "OrderPlaced", "fieldValues": {"orderId": "order-456", "customerId": "cust-123", "status": "pending"}}
186
- ],
187
- "then": {
188
- "type": "readModelAssertion",
189
- "readModel": "OrderSummary",
190
- "expected": {"orderId": "order-456", "status": "pending"}
191
- }
192
- }'
193
- \`\`\`
194
-
195
- ---
196
-
197
- ## Scenario Types Summary
198
-
199
- | Slice Type | Format | Then Contains |
200
- |------------|--------|---------------|
201
- | State-Change | Given → When (Command) → Then | Events or Error |
202
- | Automation | Given (Events) → Then | Command or noCommand |
203
- | State-View | Given → Then | Read Model Assertion |
204
-
205
- ## Best Practices
206
-
207
- 1. **Write clear descriptions** - Explain why this scenario matters and what business rule it captures
208
- 2. **Use realistic example values** - "cust-123" not "string", "2024-01-15" not "date"
209
- 3. **Name scenarios descriptively** - "Cannot cancel shipped order" not "Error case 1"
210
- 4. **Include all relevant fields** - Don't skip fields that matter for the scenario
211
- 5. **Think about state** - What events need to exist for this scenario to make sense?
212
- 6. **Cover the negative cases** - These often reveal missing business rules (use \`noCommand\` for automations)
213
- 7. **Match format to slice type** - Use Given-When-Then for state-change, Given-Then for automation
214
- `;
@@ -1,40 +0,0 @@
1
- import { meta as exploreMeta, content as exploreContent } from './guides/explore';
2
- import { meta as scenariosMeta, content as scenariosContent } from './guides/scenarios';
3
- import { meta as informationFlowMeta, content as informationFlowContent } from './guides/information-flow';
4
- import { meta as createSlicesMeta, content as createSlicesContent } from './guides/create-slices';
5
- import { meta as connectSlicesMeta, content as connectSlicesContent } from './guides/connect-slices';
6
- import { meta as codegenMeta, content as codegenContent } from './guides/codegen';
7
- const GUIDES = [
8
- { meta: exploreMeta, content: exploreContent },
9
- { meta: createSlicesMeta, content: createSlicesContent },
10
- { meta: connectSlicesMeta, content: connectSlicesContent },
11
- { meta: informationFlowMeta, content: informationFlowContent },
12
- { meta: scenariosMeta, content: scenariosContent },
13
- { meta: codegenMeta, content: codegenContent },
14
- ];
15
- export function runGuide(subcommand) {
16
- if (!subcommand) {
17
- printGuideList();
18
- return;
19
- }
20
- const guide = GUIDES.find(g => g.meta.name === subcommand);
21
- if (!guide) {
22
- console.error(`Unknown guide: ${subcommand}`);
23
- console.error(`Run "eventmodeler guide" to see available guides.`);
24
- process.exit(1);
25
- }
26
- console.log(guide.content);
27
- }
28
- function printGuideList() {
29
- console.log(`
30
- eventmodeler guide - Conceptual guides for working with event models
31
-
32
- USAGE:
33
- eventmodeler guide <name>
34
-
35
- AVAILABLE GUIDES:
36
- ${GUIDES.map(g => ` ${g.meta.name.padEnd(20)} ${g.meta.description}`).join('\n')}
37
-
38
- Run "eventmodeler guide <name>" to read a guide.
39
- `);
40
- }
@@ -1,96 +0,0 @@
1
- import { meta as exploreModelMeta, content as exploreModelContent } from './topics/explore-model';
2
- import { meta as buildSliceMeta, content as buildSliceContent } from './topics/build-slice';
3
- import { meta as connectSlicesMeta, content as connectSlicesContent } from './topics/connect-slices';
4
- import { meta as writeScenariosMeta, content as writeScenariosContent } from './topics/write-scenarios';
5
- import { meta as manipulateCanvasMeta, content as manipulateCanvasContent } from './topics/manipulate-canvas';
6
- import { meta as linkedCopiesMeta, content as linkedCopiesContent } from './topics/linked-copies';
7
- import { meta as checkCompletenessMeta, content as checkCompletenessContent } from './topics/check-completeness';
8
- import { meta as jsonReferenceMeta, content as jsonReferenceContent } from './topics/json-reference';
9
- import { meta as buildCodegenMeta, content as buildCodegenContent } from './topics/build-codegen';
10
- const TOPICS = [
11
- { meta: exploreModelMeta, content: exploreModelContent },
12
- { meta: buildSliceMeta, content: buildSliceContent },
13
- { meta: connectSlicesMeta, content: connectSlicesContent },
14
- { meta: writeScenariosMeta, content: writeScenariosContent },
15
- { meta: manipulateCanvasMeta, content: manipulateCanvasContent },
16
- { meta: linkedCopiesMeta, content: linkedCopiesContent },
17
- { meta: checkCompletenessMeta, content: checkCompletenessContent },
18
- { meta: jsonReferenceMeta, content: jsonReferenceContent },
19
- { meta: buildCodegenMeta, content: buildCodegenContent },
20
- ];
21
- export function runHelp(query) {
22
- if (!query) {
23
- printTopicIndex();
24
- return;
25
- }
26
- // Exact name match
27
- const exact = TOPICS.find(t => t.meta.name === query);
28
- if (exact) {
29
- console.log(exact.content);
30
- return;
31
- }
32
- // Fuzzy keyword match
33
- const matches = fuzzyMatch(query);
34
- if (matches.length === 0) {
35
- console.error(`No help topics matched: "${query}"`);
36
- console.error(`Run "eventmodeler help" to see all topics.`);
37
- process.exit(1);
38
- }
39
- if (matches.length === 1) {
40
- console.log(matches[0].topic.content);
41
- return;
42
- }
43
- console.log(`\nMultiple topics matched "${query}":\n`);
44
- for (const m of matches) {
45
- console.log(` ${m.topic.meta.name.padEnd(24)} ${m.topic.meta.description} (${m.score} keyword hits)`);
46
- }
47
- console.log(`\nRun "eventmodeler help <topic-name>" to read one.\n`);
48
- }
49
- function fuzzyMatch(query) {
50
- const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
51
- if (words.length === 0)
52
- return [];
53
- const scored = [];
54
- for (const topic of TOPICS) {
55
- let score = 0;
56
- const allKeywords = topic.meta.keywords.map(k => k.toLowerCase());
57
- const nameWords = topic.meta.name.toLowerCase().split('-');
58
- const descWords = topic.meta.description.toLowerCase().split(/\s+/);
59
- const searchable = [...allKeywords, ...nameWords, ...descWords];
60
- for (const word of words) {
61
- for (const kw of searchable) {
62
- if (kw === word) {
63
- score += 2;
64
- break;
65
- }
66
- else if (kw.startsWith(word) || word.startsWith(kw)) {
67
- score += 1;
68
- break;
69
- }
70
- }
71
- }
72
- if (score > 0) {
73
- scored.push({ topic, score });
74
- }
75
- }
76
- scored.sort((a, b) => b.score - a.score);
77
- return scored.slice(0, 5);
78
- }
79
- function printTopicIndex() {
80
- console.log(`
81
- eventmodeler help - Task-oriented help for the Event Modeler CLI
82
-
83
- USAGE:
84
- eventmodeler help <topic> Show a specific topic
85
- eventmodeler help <search words> Search topics by keyword
86
-
87
- TOPICS:
88
- ${TOPICS.map(t => ` ${t.meta.name.padEnd(24)} ${t.meta.description}`).join('\n')}
89
-
90
- EXAMPLES:
91
- eventmodeler help build-slice
92
- eventmodeler help json
93
- eventmodeler help place move canvas
94
- eventmodeler help scenario given when then
95
- `);
96
- }