@auto-engineer/server-generator-nestjs 0.11.16
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/.turbo/turbo-build.log +5 -0
- package/LICENSE +10 -0
- package/README.md +290 -0
- package/dist/src/codegen/entity-consolidation.d.ts +19 -0
- package/dist/src/codegen/entity-consolidation.d.ts.map +1 -0
- package/dist/src/codegen/entity-consolidation.js +134 -0
- package/dist/src/codegen/entity-consolidation.js.map +1 -0
- package/dist/src/codegen/extract/commands.d.ts +25 -0
- package/dist/src/codegen/extract/commands.d.ts.map +1 -0
- package/dist/src/codegen/extract/commands.js +67 -0
- package/dist/src/codegen/extract/commands.js.map +1 -0
- package/dist/src/codegen/extract/data-sink.d.ts +6 -0
- package/dist/src/codegen/extract/data-sink.d.ts.map +1 -0
- package/dist/src/codegen/extract/data-sink.js +78 -0
- package/dist/src/codegen/extract/data-sink.js.map +1 -0
- package/dist/src/codegen/extract/events.d.ts +10 -0
- package/dist/src/codegen/extract/events.d.ts.map +1 -0
- package/dist/src/codegen/extract/events.js +42 -0
- package/dist/src/codegen/extract/events.js.map +1 -0
- package/dist/src/codegen/extract/fields.d.ts +3 -0
- package/dist/src/codegen/extract/fields.d.ts.map +1 -0
- package/dist/src/codegen/extract/fields.js +9 -0
- package/dist/src/codegen/extract/fields.js.map +1 -0
- package/dist/src/codegen/extract/graphql.d.ts +14 -0
- package/dist/src/codegen/extract/graphql.d.ts.map +1 -0
- package/dist/src/codegen/extract/graphql.js +81 -0
- package/dist/src/codegen/extract/graphql.js.map +1 -0
- package/dist/src/codegen/extract/gwt.d.ts +6 -0
- package/dist/src/codegen/extract/gwt.d.ts.map +1 -0
- package/dist/src/codegen/extract/gwt.js +64 -0
- package/dist/src/codegen/extract/gwt.js.map +1 -0
- package/dist/src/codegen/extract/imports.d.ts +29 -0
- package/dist/src/codegen/extract/imports.d.ts.map +1 -0
- package/dist/src/codegen/extract/imports.js +55 -0
- package/dist/src/codegen/extract/imports.js.map +1 -0
- package/dist/src/codegen/extract/index.d.ts +10 -0
- package/dist/src/codegen/extract/index.d.ts.map +1 -0
- package/dist/src/codegen/extract/index.js +10 -0
- package/dist/src/codegen/extract/index.js.map +1 -0
- package/dist/src/codegen/extract/messages.d.ts +17 -0
- package/dist/src/codegen/extract/messages.d.ts.map +1 -0
- package/dist/src/codegen/extract/messages.js +172 -0
- package/dist/src/codegen/extract/messages.js.map +1 -0
- package/dist/src/codegen/extract/projection.d.ts +5 -0
- package/dist/src/codegen/extract/projection.d.ts.map +1 -0
- package/dist/src/codegen/extract/projection.js +44 -0
- package/dist/src/codegen/extract/projection.js.map +1 -0
- package/dist/src/codegen/extract/query.d.ts +14 -0
- package/dist/src/codegen/extract/query.d.ts.map +1 -0
- package/dist/src/codegen/extract/query.js +17 -0
- package/dist/src/codegen/extract/query.js.map +1 -0
- package/dist/src/codegen/extract/states.d.ts +5 -0
- package/dist/src/codegen/extract/states.d.ts.map +1 -0
- package/dist/src/codegen/extract/states.js +48 -0
- package/dist/src/codegen/extract/states.js.map +1 -0
- package/dist/src/codegen/extract/step-converter.d.ts +17 -0
- package/dist/src/codegen/extract/step-converter.d.ts.map +1 -0
- package/dist/src/codegen/extract/step-converter.js +82 -0
- package/dist/src/codegen/extract/step-converter.js.map +1 -0
- package/dist/src/codegen/extract/step-types.d.ts +29 -0
- package/dist/src/codegen/extract/step-types.d.ts.map +1 -0
- package/dist/src/codegen/extract/step-types.js +16 -0
- package/dist/src/codegen/extract/step-types.js.map +1 -0
- package/dist/src/codegen/extract/type-helpers.d.ts +13 -0
- package/dist/src/codegen/extract/type-helpers.d.ts.map +1 -0
- package/dist/src/codegen/extract/type-helpers.js +98 -0
- package/dist/src/codegen/extract/type-helpers.js.map +1 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts +9 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -0
- package/dist/src/codegen/scaffoldFromSchema.js +389 -0
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -0
- package/dist/src/codegen/templates/command/command.ts.ejs +16 -0
- package/dist/src/codegen/templates/command/handler.specs.ts.ejs +50 -0
- package/dist/src/codegen/templates/command/handler.ts.ejs +30 -0
- package/dist/src/codegen/templates/command/input.ts.ejs +23 -0
- package/dist/src/codegen/templates/command/resolver.ts.ejs +56 -0
- package/dist/src/codegen/templates/entity/entity.ts.ejs +35 -0
- package/dist/src/codegen/templates/entity/index.ts.ejs +6 -0
- package/dist/src/codegen/templates/module/app-module.ts.ejs +65 -0
- package/dist/src/codegen/templates/module/domain-module.ts.ejs +46 -0
- package/dist/src/codegen/templates/query/handler.ts.ejs +25 -0
- package/dist/src/codegen/templates/query/query.ts.ejs +1 -0
- package/dist/src/codegen/templates/query/resolver.ts.ejs +20 -0
- package/dist/src/codegen/templates/query/type.ts.ejs +24 -0
- package/dist/src/codegen/types.d.ts +38 -0
- package/dist/src/codegen/types.d.ts.map +1 -0
- package/dist/src/codegen/types.js +2 -0
- package/dist/src/codegen/types.js.map +1 -0
- package/dist/src/codegen/utils/path.d.ts +4 -0
- package/dist/src/codegen/utils/path.d.ts.map +1 -0
- package/dist/src/codegen/utils/path.js +18 -0
- package/dist/src/codegen/utils/path.js.map +1 -0
- package/dist/src/commands/generate-server.d.ts +28 -0
- package/dist/src/commands/generate-server.d.ts.map +1 -0
- package/dist/src/commands/generate-server.js +421 -0
- package/dist/src/commands/generate-server.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/shared/graphql-types.ts +19 -0
- package/dist/src/shared/main.ts +27 -0
- package/dist/src/shared/mikro-orm.config.ts +18 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +70 -0
- package/src/codegen/entity-consolidation.ts +213 -0
- package/src/codegen/extract/commands.ts +108 -0
- package/src/codegen/extract/data-sink.ts +93 -0
- package/src/codegen/extract/events.ts +63 -0
- package/src/codegen/extract/fields.ts +17 -0
- package/src/codegen/extract/graphql.ts +103 -0
- package/src/codegen/extract/gwt.ts +79 -0
- package/src/codegen/extract/imports.ts +71 -0
- package/src/codegen/extract/index.ts +9 -0
- package/src/codegen/extract/messages.ts +232 -0
- package/src/codegen/extract/projection.ts +62 -0
- package/src/codegen/extract/query.ts +28 -0
- package/src/codegen/extract/states.ts +69 -0
- package/src/codegen/extract/step-converter.ts +124 -0
- package/src/codegen/extract/step-types.ts +51 -0
- package/src/codegen/extract/type-helpers.ts +102 -0
- package/src/codegen/scaffoldFromSchema.ts +559 -0
- package/src/codegen/templates/command/command.ts.ejs +16 -0
- package/src/codegen/templates/command/handler.specs.ts.ejs +50 -0
- package/src/codegen/templates/command/handler.ts.ejs +30 -0
- package/src/codegen/templates/command/input.ts.ejs +23 -0
- package/src/codegen/templates/command/resolver.ts.ejs +56 -0
- package/src/codegen/templates/entity/entity.ts.ejs +35 -0
- package/src/codegen/templates/entity/index.ts.ejs +6 -0
- package/src/codegen/templates/module/app-module.ts.ejs +65 -0
- package/src/codegen/templates/module/domain-module.ts.ejs +46 -0
- package/src/codegen/templates/query/handler.ts.ejs +25 -0
- package/src/codegen/templates/query/query.ts.ejs +1 -0
- package/src/codegen/templates/query/resolver.ts.ejs +20 -0
- package/src/codegen/templates/query/type.ts.ejs +24 -0
- package/src/codegen/types.ts +39 -0
- package/src/codegen/utils/path.ts +20 -0
- package/src/commands/generate-server.ts +551 -0
- package/src/index.ts +10 -0
- package/src/shared/graphql-types.ts +19 -0
- package/src/shared/main.ts +27 -0
- package/src/shared/mikro-orm.config.ts +18 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
|
|
2
|
+
> @auto-engineer/server-generator-nestjs@0.11.16 build /home/runner/work/auto-engineer/auto-engineer/packages/server-generator-nestjs
|
|
3
|
+
> tsc && tsx ../../scripts/fix-esm-imports.ts && rm -rf dist/src/codegen/templates && mkdir -p dist/src/codegen && cp -r src/codegen/templates dist/src/codegen/templates && cp -r src/shared dist/src
|
|
4
|
+
|
|
5
|
+
Fixed ESM imports in dist/
|
package/LICENSE
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Elastic License 2.0
|
|
2
|
+
|
|
3
|
+
Copyright 2024 Sam Hatoum
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are licensed under the Elastic License 2.0 (the "License"). You may not use this file except in compliance with the License.
|
|
6
|
+
|
|
7
|
+
You may obtain a copy of the License at:
|
|
8
|
+
https://www.elastic.co/licensing/elastic-license
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# @auto-engineer/server-generator-nestjs
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
| --- | --- |
|
|
5
|
+
| **Status** | EXPERIMENTAL - NOT READY FOR PRODUCTION |
|
|
6
|
+
| **Stability** | APIs will change without notice |
|
|
7
|
+
| **Completeness** | Features may be incomplete or broken |
|
|
8
|
+
|
|
9
|
+
Generates complete NestJS servers from narrative domain models with CQRS, GraphQL, and MikroORM.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Purpose
|
|
14
|
+
|
|
15
|
+
Without `@auto-engineer/server-generator-nestjs`, you would have to manually scaffold NestJS modules, wire up CQRS command/query handlers, configure GraphQL resolvers, define MikroORM entities, and write boilerplate test files for every domain slice.
|
|
16
|
+
|
|
17
|
+
This package takes a narrative model (JSON) describing your domain flows and slices, then generates a fully functional NestJS server with:
|
|
18
|
+
|
|
19
|
+
- CQRS pattern via `@nestjs/cqrs` for command and query separation
|
|
20
|
+
- GraphQL API via Apollo Server with auto-generated resolvers
|
|
21
|
+
- MikroORM entities with SQLite persistence
|
|
22
|
+
- Test scaffolds for each command handler
|
|
23
|
+
|
|
24
|
+
The generated server is immediately runnable and provides a foundation for domain-driven development.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm add @auto-engineer/server-generator-nestjs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
This package generates NestJS servers from domain models. Here is how to use it.
|
|
37
|
+
|
|
38
|
+
### 1. Register the handlers
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { COMMANDS } from "@auto-engineer/server-generator-nestjs";
|
|
42
|
+
import { createMessageBus } from "@auto-engineer/message-bus";
|
|
43
|
+
|
|
44
|
+
const bus = createMessageBus();
|
|
45
|
+
COMMANDS.forEach((cmd) => bus.register(cmd));
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Send a command
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const result = await bus.send({
|
|
52
|
+
type: "GenerateServer",
|
|
53
|
+
data: {
|
|
54
|
+
modelPath: ".context/model.json",
|
|
55
|
+
destination: ".",
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
console.log(result);
|
|
60
|
+
// → { type: 'ServerGenerated', data: { serverDir: './server', ... } }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The command reads your model file, generates a complete NestJS server in the `server/` directory, and installs dependencies automatically.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## How-to Guides
|
|
68
|
+
|
|
69
|
+
### Run via CLI
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
auto generate:server --model-path=.context/model.json --destination=.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Run Programmatically
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { commandHandler } from "@auto-engineer/server-generator-nestjs";
|
|
79
|
+
|
|
80
|
+
const result = await commandHandler.handle({
|
|
81
|
+
type: "GenerateServer",
|
|
82
|
+
data: {
|
|
83
|
+
modelPath: ".context/model.json",
|
|
84
|
+
destination: "/path/to/project",
|
|
85
|
+
},
|
|
86
|
+
requestId: "req-123",
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Handle Errors
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
if (result.type === "ServerGenerationFailed") {
|
|
94
|
+
console.error(result.data.error);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Handle Per-Slice Progress
|
|
99
|
+
|
|
100
|
+
The handler emits `SliceGeneratedEvent` for each domain slice processed:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const events = await commandHandler.handle(command);
|
|
104
|
+
|
|
105
|
+
for (const event of events) {
|
|
106
|
+
if (event.type === "SliceGenerated") {
|
|
107
|
+
console.log(`Generated: ${event.data.flowName}.${event.data.sliceName}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Enable Debug Logging
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
DEBUG=auto:server-generator-nestjs:* pnpm auto generate:server
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Available debug namespaces:
|
|
119
|
+
|
|
120
|
+
- `auto:server-generator-nestjs` - General operation logging
|
|
121
|
+
- `auto:server-generator-nestjs:schema` - Model parsing details
|
|
122
|
+
- `auto:server-generator-nestjs:files` - File copy operations
|
|
123
|
+
- `auto:server-generator-nestjs:deps` - Dependency installation
|
|
124
|
+
- `auto:server-generator-nestjs:scaffold` - Scaffold generation
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## API Reference
|
|
129
|
+
|
|
130
|
+
### Exports
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { COMMANDS } from "@auto-engineer/server-generator-nestjs";
|
|
134
|
+
|
|
135
|
+
import type {
|
|
136
|
+
GenerateServerCommand,
|
|
137
|
+
GenerateServerEvents,
|
|
138
|
+
ServerGeneratedEvent,
|
|
139
|
+
ServerGenerationFailedEvent,
|
|
140
|
+
SliceGeneratedEvent,
|
|
141
|
+
} from "@auto-engineer/server-generator-nestjs";
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Commands
|
|
145
|
+
|
|
146
|
+
| Command | CLI Alias | Description |
|
|
147
|
+
| ---------------- | ----------------- | --------------------------------- |
|
|
148
|
+
| `GenerateServer` | `generate:server` | Generate NestJS server from model |
|
|
149
|
+
|
|
150
|
+
### Command Fields
|
|
151
|
+
|
|
152
|
+
| Field | Type | Required | Description |
|
|
153
|
+
| ------------- | -------- | -------- | ------------------------------------------ |
|
|
154
|
+
| `modelPath` | `string` | Yes | Path to the JSON model file |
|
|
155
|
+
| `destination` | `string` | Yes | Destination directory for generated server |
|
|
156
|
+
|
|
157
|
+
### Events
|
|
158
|
+
|
|
159
|
+
| Event | Description |
|
|
160
|
+
| ----------------------------- | -------------------------------- |
|
|
161
|
+
| `ServerGeneratedEvent` | Emitted on successful generation |
|
|
162
|
+
| `ServerGenerationFailedEvent` | Emitted when generation fails |
|
|
163
|
+
| `SliceGeneratedEvent` | Emitted for each slice processed |
|
|
164
|
+
|
|
165
|
+
### ServerGeneratedEvent Data
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
{
|
|
169
|
+
modelPath: string;
|
|
170
|
+
destination: string;
|
|
171
|
+
serverDir: string;
|
|
172
|
+
contextSchemaGraphQL?: string;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### ServerGenerationFailedEvent Data
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
{
|
|
180
|
+
modelPath: string;
|
|
181
|
+
destination: string;
|
|
182
|
+
error: string;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### SliceGeneratedEvent Data
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
{
|
|
190
|
+
flowName: string;
|
|
191
|
+
sliceName: string;
|
|
192
|
+
sliceType: string;
|
|
193
|
+
schemaPath: string;
|
|
194
|
+
slicePath: string;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Architecture
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
src/
|
|
204
|
+
├── index.ts # Package entry point (exports COMMANDS)
|
|
205
|
+
├── commands/
|
|
206
|
+
│ └── generate-server.ts # Main command handler
|
|
207
|
+
├── codegen/
|
|
208
|
+
│ ├── scaffoldFromSchema.ts # Scaffold orchestrator
|
|
209
|
+
│ ├── entity-consolidation.ts # Entity field merging
|
|
210
|
+
│ ├── types.ts # Core type definitions
|
|
211
|
+
│ ├── extract/ # Message/GWT extraction
|
|
212
|
+
│ │ ├── commands.ts # Command extraction
|
|
213
|
+
│ │ ├── events.ts # Event extraction
|
|
214
|
+
│ │ ├── states.ts # State extraction
|
|
215
|
+
│ │ ├── fields.ts # Field extraction
|
|
216
|
+
│ │ ├── gwt.ts # GWT mapping builders
|
|
217
|
+
│ │ ├── graphql.ts # GraphQL query parsing
|
|
218
|
+
│ │ └── imports.ts # Cross-slice imports
|
|
219
|
+
│ ├── templates/ # EJS templates
|
|
220
|
+
│ │ ├── command/ # Command slice templates
|
|
221
|
+
│ │ ├── query/ # Query slice templates
|
|
222
|
+
│ │ ├── entity/ # Entity templates
|
|
223
|
+
│ │ └── module/ # NestJS module templates
|
|
224
|
+
│ └── utils/
|
|
225
|
+
│ └── path.ts # Path utilities
|
|
226
|
+
└── shared/ # Files copied to generated server
|
|
227
|
+
├── main.ts # NestJS bootstrap
|
|
228
|
+
├── mikro-orm.config.ts # Database configuration
|
|
229
|
+
└── graphql-types.ts # Shared GraphQL types
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Generated Server Structure
|
|
233
|
+
|
|
234
|
+
The command generates the following structure:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
server/
|
|
238
|
+
├── package.json
|
|
239
|
+
├── tsconfig.json
|
|
240
|
+
├── vitest.config.ts
|
|
241
|
+
├── mikro-orm.config.ts
|
|
242
|
+
└── src/
|
|
243
|
+
├── main.ts
|
|
244
|
+
└── domain/
|
|
245
|
+
├── shared/
|
|
246
|
+
│ └── graphql-types.ts
|
|
247
|
+
├── {flow-name}/
|
|
248
|
+
│ ├── {slice-name}/
|
|
249
|
+
│ │ ├── command.ts
|
|
250
|
+
│ │ ├── input.ts
|
|
251
|
+
│ │ ├── handler.ts
|
|
252
|
+
│ │ ├── handler.specs.ts
|
|
253
|
+
│ │ └── resolver.ts
|
|
254
|
+
│ └── entities/
|
|
255
|
+
│ └── {entity}.entity.ts
|
|
256
|
+
└── {flow-name}.module.ts
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Dependencies
|
|
260
|
+
|
|
261
|
+
**Monorepo:**
|
|
262
|
+
|
|
263
|
+
| Package | Usage |
|
|
264
|
+
| -------------------------- | ----------------------------- |
|
|
265
|
+
| `@auto-engineer/narrative` | Domain model type definitions |
|
|
266
|
+
|
|
267
|
+
**External:**
|
|
268
|
+
|
|
269
|
+
| Package | Usage |
|
|
270
|
+
| ------------------- | --------------------------- |
|
|
271
|
+
| `@nestjs/cqrs` | CQRS command/query pattern |
|
|
272
|
+
| `@nestjs/graphql` | GraphQL schema generation |
|
|
273
|
+
| `@nestjs/apollo` | Apollo Server integration |
|
|
274
|
+
| `@mikro-orm/core` | ORM for entity persistence |
|
|
275
|
+
| `@mikro-orm/sqlite` | SQLite database driver |
|
|
276
|
+
| `ejs` | Template rendering engine |
|
|
277
|
+
| `prettier` | Generated code formatting |
|
|
278
|
+
| `change-case` | Naming convention utilities |
|
|
279
|
+
| `execa` | Dependency installation |
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Known Limitations
|
|
284
|
+
|
|
285
|
+
This generator is experimental. Current limitations include:
|
|
286
|
+
|
|
287
|
+
- Schema extraction is incomplete for complex slice types
|
|
288
|
+
- Generated code may require manual fixes
|
|
289
|
+
- Test coverage is minimal
|
|
290
|
+
- Only SQLite persistence is supported
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Narrative } from '@auto-engineer/narrative';
|
|
2
|
+
import type { MessageDefinition } from './types.js';
|
|
3
|
+
export interface EntityField {
|
|
4
|
+
name: string;
|
|
5
|
+
tsType: string;
|
|
6
|
+
nullable: boolean;
|
|
7
|
+
isPrimary: boolean;
|
|
8
|
+
isEnum: boolean;
|
|
9
|
+
enumName?: string;
|
|
10
|
+
indexed: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface ConsolidatedEntity {
|
|
13
|
+
entityName: string;
|
|
14
|
+
tableName: string;
|
|
15
|
+
fields: EntityField[];
|
|
16
|
+
enumImports: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function consolidateEntityFields(flow: Narrative, messages: MessageDefinition[], unionToEnumName: Map<string, string>): ConsolidatedEntity;
|
|
19
|
+
//# sourceMappingURL=entity-consolidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-consolidation.d.ts","sourceRoot":"","sources":["../../../src/codegen/entity-consolidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAI1D,OAAO,KAAK,EAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIpE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAkKD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,kBAAkB,CAuBpB"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { camelCase, pascalCase } from 'change-case';
|
|
2
|
+
import createDebug from 'debug';
|
|
3
|
+
import { extractMessagesFromSpecs } from './extract/index.js';
|
|
4
|
+
const debug = createDebug('auto:server-generator-nestjs:entity');
|
|
5
|
+
function isEnumType(tsType) {
|
|
6
|
+
const cleanType = tsType.replace(/\s*\|\s*null\b/g, '').trim();
|
|
7
|
+
return /^"[^"]+"(\s*\|\s*"[^"]+")+$/.test(cleanType) || /^'[^']+'(\s*\|\s*'[^']+)+$/.test(cleanType);
|
|
8
|
+
}
|
|
9
|
+
function detectPrimaryKeyField(fields, flowName) {
|
|
10
|
+
const idCandidates = [`${camelCase(flowName)}Id`, 'id', `${camelCase(flowName)}ID`, 'ID'];
|
|
11
|
+
for (const candidate of idCandidates) {
|
|
12
|
+
const field = fields.find((f) => f.name === candidate);
|
|
13
|
+
if (field) {
|
|
14
|
+
return field.name;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const stringFields = fields.filter((f) => f.tsType === 'string' && f.name.toLowerCase().includes('id'));
|
|
18
|
+
if (stringFields.length > 0) {
|
|
19
|
+
return stringFields[0].name;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
function shouldIndexField(fieldName, tsType) {
|
|
24
|
+
const indexableNames = ['status', 'type', 'category', 'state'];
|
|
25
|
+
const nameLower = fieldName.toLowerCase();
|
|
26
|
+
if (indexableNames.some((name) => nameLower.includes(name))) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
if (isEnumType(tsType)) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
function processFieldsFromMessages(fields, fieldMap, unionToEnumName, enumsUsed) {
|
|
35
|
+
for (const field of fields) {
|
|
36
|
+
if (field.name === 'now')
|
|
37
|
+
continue;
|
|
38
|
+
if (!fieldMap.has(field.name)) {
|
|
39
|
+
const isEnum = isEnumType(field.tsType);
|
|
40
|
+
const cleanType = field.tsType.replace(/\s*\|\s*null\b/g, '').trim();
|
|
41
|
+
let enumName;
|
|
42
|
+
if (isEnum) {
|
|
43
|
+
const matches = cleanType.match(/'([^']+)'/g);
|
|
44
|
+
const values = matches !== null ? matches.map((v) => v.slice(1, -1)) : [];
|
|
45
|
+
const normalized = values
|
|
46
|
+
.sort()
|
|
47
|
+
.map((v) => `'${v}'`)
|
|
48
|
+
.join(' | ');
|
|
49
|
+
enumName = unionToEnumName.get(normalized);
|
|
50
|
+
if (typeof enumName === 'string' && enumName.length > 0) {
|
|
51
|
+
enumsUsed.add(enumName);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
fieldMap.set(field.name, {
|
|
55
|
+
name: field.name,
|
|
56
|
+
tsType: field.tsType,
|
|
57
|
+
nullable: /\|\s*null\b/.test(field.tsType),
|
|
58
|
+
isPrimary: false,
|
|
59
|
+
isEnum,
|
|
60
|
+
enumName,
|
|
61
|
+
indexed: false,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function processMessagesWithFields(messageArray, messageLabel, fieldMap, unionToEnumName, enumsUsed) {
|
|
67
|
+
for (const msg of messageArray) {
|
|
68
|
+
debug(' %s: %s with %d fields', messageLabel, msg.type, msg.fields.length);
|
|
69
|
+
if (msg.fields.length > 0) {
|
|
70
|
+
processFieldsFromMessages(msg.fields, fieldMap, unionToEnumName, enumsUsed);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function processCommandSlice(slice, messages, fieldMap, unionToEnumName, enumsUsed) {
|
|
75
|
+
debug(' Processing slice: %s (type: %s)', slice.name, slice.type);
|
|
76
|
+
const extracted = extractMessagesFromSpecs(slice, messages);
|
|
77
|
+
processMessagesWithFields(extracted.commands, 'Command', fieldMap, unionToEnumName, enumsUsed);
|
|
78
|
+
processMessagesWithFields(extracted.events, 'Event', fieldMap, unionToEnumName, enumsUsed);
|
|
79
|
+
}
|
|
80
|
+
function processQuerySlice(slice, messages, fieldMap, unionToEnumName, enumsUsed) {
|
|
81
|
+
debug(' Processing slice: %s (type: %s)', slice.name, slice.type);
|
|
82
|
+
const extracted = extractMessagesFromSpecs(slice, messages);
|
|
83
|
+
processMessagesWithFields(extracted.states, 'State', fieldMap, unionToEnumName, enumsUsed);
|
|
84
|
+
}
|
|
85
|
+
function collectFieldsFromSlices(flow, messages, fieldMap, unionToEnumName, enumsUsed) {
|
|
86
|
+
for (const slice of flow.slices) {
|
|
87
|
+
if (slice.type === 'experience')
|
|
88
|
+
continue;
|
|
89
|
+
if (slice.type === 'command') {
|
|
90
|
+
processCommandSlice(slice, messages, fieldMap, unionToEnumName, enumsUsed);
|
|
91
|
+
}
|
|
92
|
+
if (slice.type === 'query') {
|
|
93
|
+
processQuerySlice(slice, messages, fieldMap, unionToEnumName, enumsUsed);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function markPrimaryKeyAndIndexes(fields, fieldMap, flowName) {
|
|
98
|
+
const primaryKeyField = detectPrimaryKeyField(fields, flowName);
|
|
99
|
+
if (typeof primaryKeyField === 'string' && primaryKeyField.length > 0) {
|
|
100
|
+
const field = fieldMap.get(primaryKeyField);
|
|
101
|
+
if (field !== undefined) {
|
|
102
|
+
field.isPrimary = true;
|
|
103
|
+
debug(' Detected primary key: %s', primaryKeyField);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
debug(' WARNING: No primary key detected for flow: %s', flowName);
|
|
108
|
+
}
|
|
109
|
+
for (const field of fields) {
|
|
110
|
+
if (!field.isPrimary && shouldIndexField(field.name, field.tsType)) {
|
|
111
|
+
field.indexed = true;
|
|
112
|
+
debug(' Marking field for indexing: %s', field.name);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function consolidateEntityFields(flow, messages, unionToEnumName) {
|
|
117
|
+
debug('Consolidating entity fields for flow: %s', flow.name);
|
|
118
|
+
const fieldMap = new Map();
|
|
119
|
+
const enumsUsed = new Set();
|
|
120
|
+
collectFieldsFromSlices(flow, messages, fieldMap, unionToEnumName, enumsUsed);
|
|
121
|
+
const fields = Array.from(fieldMap.values());
|
|
122
|
+
markPrimaryKeyAndIndexes(fields, fieldMap, flow.name);
|
|
123
|
+
const entityName = pascalCase(flow.name) + 'Entity';
|
|
124
|
+
const tableName = camelCase(flow.name) + 's';
|
|
125
|
+
debug('Consolidated entity: %s with %d fields', entityName, fields.length);
|
|
126
|
+
debug(' Enum imports: %o', Array.from(enumsUsed));
|
|
127
|
+
return {
|
|
128
|
+
entityName,
|
|
129
|
+
tableName,
|
|
130
|
+
fields,
|
|
131
|
+
enumImports: Array.from(enumsUsed),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=entity-consolidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-consolidation.js","sourceRoot":"","sources":["../../../src/codegen/entity-consolidation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Message, MessageDefinition } from '../types';
|
|
2
|
+
import type { CommandExample, EventExample } from './step-types';
|
|
3
|
+
export declare function extractCommandsFromGwt(gwtSpecs: Array<{
|
|
4
|
+
given?: Array<EventExample | unknown>;
|
|
5
|
+
when?: CommandExample | EventExample | unknown[];
|
|
6
|
+
then: Array<EventExample | unknown | {
|
|
7
|
+
errorType: string;
|
|
8
|
+
message?: string;
|
|
9
|
+
}>;
|
|
10
|
+
}>, allMessages: MessageDefinition[]): {
|
|
11
|
+
commands: Message[];
|
|
12
|
+
commandSchemasByName: Record<string, Message>;
|
|
13
|
+
};
|
|
14
|
+
export declare function extractCommandsFromThen(gwtSpecs: Array<{
|
|
15
|
+
given?: Array<EventExample | unknown>;
|
|
16
|
+
when?: CommandExample | EventExample | unknown[];
|
|
17
|
+
then: Array<EventExample | unknown | {
|
|
18
|
+
errorType: string;
|
|
19
|
+
message?: string;
|
|
20
|
+
}>;
|
|
21
|
+
}>, allMessages: MessageDefinition[]): {
|
|
22
|
+
commands: Message[];
|
|
23
|
+
commandSchemasByName: Record<string, Message>;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/codegen/extract/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAoBjE,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,cAAc,GAAG,YAAY,GAAG,OAAO,EAAE,CAAC;IACjD,IAAI,EAAE,KAAK,CAAC,YAAY,GAAG,OAAO,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/E,CAAC,EACF,WAAW,EAAE,iBAAiB,EAAE,GAC/B;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAwBxE;AAgCD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,cAAc,GAAG,YAAY,GAAG,OAAO,EAAE,CAAC;IACjD,IAAI,EAAE,KAAK,CAAC,YAAY,GAAG,OAAO,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/E,CAAC,EACF,WAAW,EAAE,iBAAiB,EAAE,GAC/B;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAexE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { extractFieldsFromMessage } from './fields.js';
|
|
2
|
+
function createCommandMessage(commandRef, allMessages, source) {
|
|
3
|
+
const fields = extractFieldsFromMessage(commandRef, 'command', allMessages);
|
|
4
|
+
if (fields.length === 0 && source === 'then') {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
type: commandRef,
|
|
9
|
+
fields,
|
|
10
|
+
source,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function extractCommandsFromGwt(gwtSpecs, allMessages) {
|
|
14
|
+
const commandSchemasByName = {};
|
|
15
|
+
const commands = gwtSpecs
|
|
16
|
+
.map((gwt) => {
|
|
17
|
+
const cmd = gwt.when;
|
|
18
|
+
if (Array.isArray(cmd) ||
|
|
19
|
+
typeof cmd !== 'object' ||
|
|
20
|
+
cmd === null ||
|
|
21
|
+
!('commandRef' in cmd) ||
|
|
22
|
+
typeof cmd.commandRef !== 'string' ||
|
|
23
|
+
!cmd.commandRef)
|
|
24
|
+
return undefined;
|
|
25
|
+
const command = createCommandMessage(cmd.commandRef, allMessages, 'when');
|
|
26
|
+
if (command) {
|
|
27
|
+
commandSchemasByName[cmd.commandRef] = command;
|
|
28
|
+
}
|
|
29
|
+
return command;
|
|
30
|
+
})
|
|
31
|
+
.filter((cmd) => cmd !== undefined);
|
|
32
|
+
return { commands, commandSchemasByName };
|
|
33
|
+
}
|
|
34
|
+
function isValidCommandExample(commandExample) {
|
|
35
|
+
return (typeof commandExample === 'object' &&
|
|
36
|
+
commandExample !== null &&
|
|
37
|
+
'commandRef' in commandExample &&
|
|
38
|
+
typeof commandExample.commandRef === 'string' &&
|
|
39
|
+
!!commandExample.commandRef);
|
|
40
|
+
}
|
|
41
|
+
function processCommandExample(commandExample, commands, commandSchemasByName, allMessages) {
|
|
42
|
+
if (!isValidCommandExample(commandExample)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const commandRef = commandExample.commandRef;
|
|
46
|
+
if (!(commandRef in commandSchemasByName)) {
|
|
47
|
+
const command = createCommandMessage(commandRef, allMessages, 'then');
|
|
48
|
+
if (command) {
|
|
49
|
+
commands.push(command);
|
|
50
|
+
commandSchemasByName[commandRef] = command;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function extractCommandsFromThen(gwtSpecs, allMessages) {
|
|
55
|
+
const commands = [];
|
|
56
|
+
const commandSchemasByName = {};
|
|
57
|
+
for (const gwt of gwtSpecs) {
|
|
58
|
+
if (!Array.isArray(gwt.then)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const commandExample of gwt.then) {
|
|
62
|
+
processCommandExample(commandExample, commands, commandSchemasByName, allMessages);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { commands, commandSchemasByName };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../../src/codegen/extract/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-sink.d.ts","sourceRoot":"","sources":["../../../../src/codegen/extract/data-sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AA2EtD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAiB7F"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { extractGwtSpecsFromSlice } from './step-converter.js';
|
|
2
|
+
function resolveStreamId(stream, exampleData) {
|
|
3
|
+
return stream.replace(/\$\{([^}]+)\}/g, (_, key) => String(exampleData?.[key] ?? 'unknown'));
|
|
4
|
+
}
|
|
5
|
+
function extractExampleDataFromReact(firstSpec) {
|
|
6
|
+
if (Array.isArray(firstSpec.when)) {
|
|
7
|
+
const firstWhen = firstSpec.when[0];
|
|
8
|
+
return typeof firstWhen?.exampleData === 'object' && firstWhen.exampleData !== null ? firstWhen.exampleData : {};
|
|
9
|
+
}
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
function extractExampleDataFromCommand(firstSpec) {
|
|
13
|
+
const then = firstSpec.then;
|
|
14
|
+
const firstExample = then.find((t) => 'exampleData' in t);
|
|
15
|
+
return typeof firstExample?.exampleData === 'object' && firstExample.exampleData !== null
|
|
16
|
+
? firstExample.exampleData
|
|
17
|
+
: {};
|
|
18
|
+
}
|
|
19
|
+
function extractExampleDataFromQuery(firstSpec) {
|
|
20
|
+
if (Array.isArray(firstSpec.when)) {
|
|
21
|
+
const firstWhen = firstSpec.when[0];
|
|
22
|
+
return typeof firstWhen?.exampleData === 'object' && firstWhen.exampleData !== null ? firstWhen.exampleData : {};
|
|
23
|
+
}
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
function extractExampleDataFromSpecs(slice, gwtSpecs) {
|
|
27
|
+
if (gwtSpecs.length === 0) {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
const firstSpec = gwtSpecs[0];
|
|
31
|
+
switch (slice.type) {
|
|
32
|
+
case 'react':
|
|
33
|
+
return extractExampleDataFromReact(firstSpec);
|
|
34
|
+
case 'command':
|
|
35
|
+
return extractExampleDataFromCommand(firstSpec);
|
|
36
|
+
case 'query':
|
|
37
|
+
return extractExampleDataFromQuery(firstSpec);
|
|
38
|
+
default:
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function isValidStreamSink(item) {
|
|
43
|
+
return (typeof item === 'object' &&
|
|
44
|
+
item !== null &&
|
|
45
|
+
'destination' in item &&
|
|
46
|
+
typeof item.destination === 'object' &&
|
|
47
|
+
item.destination !== null &&
|
|
48
|
+
'type' in item.destination &&
|
|
49
|
+
item.destination.type === 'stream' &&
|
|
50
|
+
'pattern' in item.destination &&
|
|
51
|
+
typeof item.destination.pattern === 'string');
|
|
52
|
+
}
|
|
53
|
+
function processStreamSink(item, exampleData) {
|
|
54
|
+
if (!isValidStreamSink(item)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const streamPattern = item.destination.pattern;
|
|
58
|
+
const streamId = streamPattern.length > 0 ? resolveStreamId(streamPattern, exampleData) : undefined;
|
|
59
|
+
return { streamPattern, streamId };
|
|
60
|
+
}
|
|
61
|
+
export function getStreamFromSink(slice) {
|
|
62
|
+
if (!('server' in slice))
|
|
63
|
+
return {};
|
|
64
|
+
const gwtSpecs = extractGwtSpecsFromSlice(slice);
|
|
65
|
+
const exampleData = extractExampleDataFromSpecs(slice, gwtSpecs);
|
|
66
|
+
if (!('server' in slice) || slice.server == null || !('data' in slice.server) || !Array.isArray(slice.server.data)) {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
const serverData = slice.server.data;
|
|
70
|
+
for (const item of serverData) {
|
|
71
|
+
const result = processStreamSink(item, exampleData);
|
|
72
|
+
if (result) {
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=data-sink.js.map
|