@ackplus/nest-dynamic-templates 1.1.10 โ 1.1.12
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/README.md +121 -539
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +19 -15
- package/dist/test/helpers.d.ts +0 -4
- package/dist/test/helpers.js +0 -34
- package/dist/test/helpers.js.map +0 -1
- package/dist/test/test-database.config.d.ts +0 -4
- package/dist/test/test-database.config.js +0 -24
- package/dist/test/test-database.config.js.map +0 -1
- package/dist/test/test.setup.d.ts +0 -3
- package/dist/test/test.setup.js +0 -29
- package/dist/test/test.setup.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,616 +1,198 @@
|
|
|
1
1
|
# @ackplus/nest-dynamic-templates
|
|
2
2
|
|
|
3
|
-
A powerful and flexible
|
|
3
|
+
A powerful and flexible dynamic template rendering library for NestJS applications. Support for multiple template engines (Nunjucks, Handlebars, EJS, Pug) and content languages (HTML, MJML, Markdown, Text), with built-in database storage and layout management.
|
|
4
4
|
|
|
5
5
|
## โจ Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- ๐งช **Test-Friendly** - Perfect for testing and development
|
|
14
|
-
- ๐ **TypeScript** - Full TypeScript support with type safety
|
|
7
|
+
- ๐ **Multiple Engines** - Support for Nunjucks, Handlebars, EJS, and Pug
|
|
8
|
+
- ๐ **Multi-Format** - Render HTML, MJML, Markdown, or Plain Text
|
|
9
|
+
- ๐๏ธ **Database Storage** - Store templates in your database (TypeORM support)
|
|
10
|
+
- ๐จ **Layout Support** - Create reusable layouts for your templates
|
|
11
|
+
- ๐ **Scope & Locale** - Manage templates by scope (system/user/tenant) and locale (en/es/etc.)
|
|
12
|
+
- ๐ **Dynamic Rendering** - Render templates with dynamic context at runtime
|
|
15
13
|
|
|
16
14
|
## ๐ฆ Installation
|
|
17
15
|
|
|
18
16
|
```bash
|
|
19
|
-
npm install @ackplus/nest-dynamic-templates
|
|
17
|
+
npm install @ackplus/nest-dynamic-templates
|
|
20
18
|
# or
|
|
21
|
-
pnpm add @ackplus/nest-dynamic-templates
|
|
19
|
+
pnpm add @ackplus/nest-dynamic-templates
|
|
22
20
|
# or
|
|
23
|
-
yarn add @ackplus/nest-dynamic-templates
|
|
21
|
+
yarn add @ackplus/nest-dynamic-templates
|
|
24
22
|
```
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
### Peer Dependencies
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
npm install -D ts-node typescript
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## ๐ Quick Start (5 Steps)
|
|
33
|
-
|
|
34
|
-
### Step 1: Create Entity
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
// src/entities/user.entity.ts
|
|
38
|
-
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
39
|
-
|
|
40
|
-
@Entity('users')
|
|
41
|
-
export class User {
|
|
42
|
-
@PrimaryGeneratedColumn()
|
|
43
|
-
id: number;
|
|
44
|
-
|
|
45
|
-
@Column()
|
|
46
|
-
name: string;
|
|
47
|
-
|
|
48
|
-
@Column({ unique: true })
|
|
49
|
-
email: string;
|
|
50
|
-
|
|
51
|
-
@Column()
|
|
52
|
-
role: string;
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Step 2: Create Factory
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// src/factories/user.factory.ts
|
|
60
|
-
import { Factory } from '@ackplus/nest-dynamic-templates';
|
|
61
|
-
|
|
62
|
-
export class UserFactory {
|
|
63
|
-
@Factory((faker) => faker.person.fullName())
|
|
64
|
-
name: string;
|
|
65
|
-
|
|
66
|
-
@Factory((faker) => faker.internet.email())
|
|
67
|
-
email: string;
|
|
68
|
-
|
|
69
|
-
@Factory((faker) => faker.helpers.arrayElement(['admin', 'user', 'guest']))
|
|
70
|
-
role: string;
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Step 3: Create Seeder
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
// src/seeders/user.seeder.ts
|
|
78
|
-
import { Injectable } from '@nestjs/common';
|
|
79
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
80
|
-
import { Repository } from 'typeorm';
|
|
81
|
-
import { Seeder, DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
82
|
-
import { User } from '../entities/user.entity';
|
|
83
|
-
import { UserFactory } from '../factories/user.factory';
|
|
84
|
-
|
|
85
|
-
@Injectable()
|
|
86
|
-
export class UserSeeder implements Seeder {
|
|
87
|
-
constructor(
|
|
88
|
-
@InjectRepository(User)
|
|
89
|
-
private readonly userRepository: Repository<User>,
|
|
90
|
-
) {}
|
|
91
|
-
|
|
92
|
-
async seed(): Promise<void> {
|
|
93
|
-
// Create factory instance
|
|
94
|
-
const factory = DataFactory.createForClass(UserFactory);
|
|
95
|
-
|
|
96
|
-
// Generate 10 users
|
|
97
|
-
const users = factory.generate(10);
|
|
98
|
-
|
|
99
|
-
// Save to database
|
|
100
|
-
await this.userRepository.save(users);
|
|
101
|
-
|
|
102
|
-
console.log('โ
Seeded 10 users');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async drop(): Promise<void> {
|
|
106
|
-
// Clear all users
|
|
107
|
-
await this.userRepository.delete({});
|
|
108
|
-
|
|
109
|
-
console.log('๐๏ธ Dropped all users');
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Step 4: Create Configuration File
|
|
115
|
-
|
|
116
|
-
Create `seeder.config.ts` in your **project root**:
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// seeder.config.ts
|
|
120
|
-
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
121
|
-
import { User } from './src/entities/user.entity';
|
|
122
|
-
import { UserSeeder } from './src/seeders/user.seeder';
|
|
123
|
-
|
|
124
|
-
export default {
|
|
125
|
-
imports: [
|
|
126
|
-
// Database configuration
|
|
127
|
-
TypeOrmModule.forRoot({
|
|
128
|
-
type: 'postgres',
|
|
129
|
-
host: 'localhost',
|
|
130
|
-
port: 5432,
|
|
131
|
-
username: 'postgres',
|
|
132
|
-
password: 'postgres',
|
|
133
|
-
database: 'mydb',
|
|
134
|
-
entities: [User],
|
|
135
|
-
synchronize: true,
|
|
136
|
-
}),
|
|
137
|
-
|
|
138
|
-
// Register repositories
|
|
139
|
-
TypeOrmModule.forFeature([User]),
|
|
140
|
-
],
|
|
141
|
-
|
|
142
|
-
// List seeders (run in order)
|
|
143
|
-
seeders: [UserSeeder],
|
|
144
|
-
};
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Step 5: Run Seeder
|
|
148
|
-
|
|
149
|
-
Add script to `package.json`:
|
|
150
|
-
|
|
151
|
-
```json
|
|
152
|
-
{
|
|
153
|
-
"scripts": {
|
|
154
|
-
"seed": "nest-seed -c seeder.config.ts"
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Run it:
|
|
26
|
+
You must install the necessary peer dependencies depending on which engines and database you use:
|
|
160
27
|
|
|
161
28
|
```bash
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
**That's it!** Your database is now seeded! ๐
|
|
29
|
+
# Core dependencies
|
|
30
|
+
npm install @nestjs/common @nestjs/core @nestjs/typeorm typeorm reflect-metadata
|
|
166
31
|
|
|
167
|
-
|
|
32
|
+
# Template Engines (install at least one)
|
|
33
|
+
npm install nunjucks @types/nunjucks
|
|
34
|
+
# OR
|
|
35
|
+
npm install handlebars
|
|
36
|
+
# OR
|
|
37
|
+
npm install ejs @types/ejs
|
|
38
|
+
# OR
|
|
39
|
+
npm install pug @types/pug
|
|
168
40
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# Run all seeders
|
|
173
|
-
nest-seed -c seeder.config.ts
|
|
174
|
-
|
|
175
|
-
# Drop and reseed
|
|
176
|
-
nest-seed -c seeder.config.ts --refresh
|
|
177
|
-
|
|
178
|
-
# Run specific seeder
|
|
179
|
-
nest-seed -c seeder.config.ts --name UserSeeder
|
|
180
|
-
|
|
181
|
-
# Run multiple seeders
|
|
182
|
-
nest-seed -c seeder.config.ts --name UserSeeder ProductSeeder
|
|
41
|
+
# Language Support (optional)
|
|
42
|
+
npm install mjml @types/mjml # For MJML support
|
|
43
|
+
npm install htmlparser2 # For HTML processing
|
|
183
44
|
```
|
|
184
45
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
| Option | Alias | Description | Default |
|
|
188
|
-
|--------|-------|-------------|---------|
|
|
189
|
-
| `--config` | `-c` | Path to configuration file | (required) |
|
|
190
|
-
| `--refresh` | `-r` | Drop data before seeding | `false` |
|
|
191
|
-
| `--name` | `-n` | Run specific seeder(s) | (all) |
|
|
192
|
-
| `--dummyData` | `-d` | Include dummy data flag | `false` |
|
|
193
|
-
| `--help` | `-h` | Show help | |
|
|
194
|
-
|
|
195
|
-
### Package.json Scripts
|
|
196
|
-
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"scripts": {
|
|
200
|
-
"seed": "nest-seed -c seeder.config.ts",
|
|
201
|
-
"seed:refresh": "nest-seed -c seeder.config.ts -r",
|
|
202
|
-
"seed:users": "nest-seed -c seeder.config.ts -n UserSeeder",
|
|
203
|
-
"seed:watch": "nodemon --watch src/seeders --ext ts --exec nest-seed -c seeder.config.ts"
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
```
|
|
46
|
+
## ๐ Quick Start
|
|
207
47
|
|
|
208
|
-
|
|
48
|
+
### 1. Import Module
|
|
209
49
|
|
|
210
|
-
|
|
50
|
+
Import `NestDynamicTemplatesModule` into your root `AppModule`. You must configure it with `TypeORM`.
|
|
211
51
|
|
|
212
52
|
```typescript
|
|
213
|
-
|
|
53
|
+
import { Module } from '@nestjs/common';
|
|
214
54
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
215
|
-
import {
|
|
216
|
-
import { UserSeeder, PostSeeder, CommentSeeder } from './src/seeders';
|
|
55
|
+
import { NestDynamicTemplatesModule, TemplateEngineEnum, TemplateLanguageEnum } from '@ackplus/nest-dynamic-templates';
|
|
217
56
|
|
|
218
|
-
|
|
57
|
+
@Module({
|
|
219
58
|
imports: [
|
|
220
59
|
TypeOrmModule.forRoot({
|
|
221
|
-
|
|
222
|
-
host: process.env.DB_HOST || 'localhost',
|
|
223
|
-
port: parseInt(process.env.DB_PORT) || 5432,
|
|
224
|
-
username: process.env.DB_USER || 'postgres',
|
|
225
|
-
password: process.env.DB_PASSWORD || 'postgres',
|
|
226
|
-
database: process.env.DB_NAME || 'mydb',
|
|
227
|
-
entities: [User, Post, Comment],
|
|
228
|
-
synchronize: true,
|
|
60
|
+
// ... your database config
|
|
229
61
|
}),
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
### MongoDB/Mongoose Example
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
// seeder.config.ts
|
|
240
|
-
import { MongooseModule } from '@nestjs/mongoose';
|
|
241
|
-
import { User, UserSchema } from './src/schemas/user.schema';
|
|
242
|
-
import { UserSeeder } from './src/seeders/user.seeder';
|
|
243
|
-
|
|
244
|
-
export default {
|
|
245
|
-
imports: [
|
|
246
|
-
MongooseModule.forRoot('mongodb://localhost/mydb'),
|
|
247
|
-
MongooseModule.forFeature([
|
|
248
|
-
{ name: User.name, schema: UserSchema }
|
|
249
|
-
]),
|
|
250
|
-
],
|
|
251
|
-
seeders: [UserSeeder],
|
|
252
|
-
};
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### SQLite Example
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
// seeder.config.ts
|
|
259
|
-
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
260
|
-
import { User } from './src/entities/user.entity';
|
|
261
|
-
import { UserSeeder } from './src/seeders/user.seeder';
|
|
262
|
-
|
|
263
|
-
export default {
|
|
264
|
-
imports: [
|
|
265
|
-
TypeOrmModule.forRoot({
|
|
266
|
-
type: 'sqlite',
|
|
267
|
-
database: 'database.sqlite',
|
|
268
|
-
entities: [User],
|
|
269
|
-
synchronize: true,
|
|
62
|
+
NestDynamicTemplatesModule.forRoot({
|
|
63
|
+
engines: {
|
|
64
|
+
template: [TemplateEngineEnum.NUNJUCKS], // Enable specific engines
|
|
65
|
+
language: [TemplateLanguageEnum.HTML, TemplateLanguageEnum.MJML]
|
|
66
|
+
},
|
|
67
|
+
isGlobal: true, // Optional: make module global
|
|
270
68
|
}),
|
|
271
|
-
TypeOrmModule.forFeature([User]),
|
|
272
69
|
],
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## ๐ญ Factories
|
|
278
|
-
|
|
279
|
-
### Basic Factory
|
|
280
|
-
|
|
281
|
-
```typescript
|
|
282
|
-
import { Factory } from '@ackplus/nest-dynamic-templates';
|
|
283
|
-
|
|
284
|
-
export class UserFactory {
|
|
285
|
-
@Factory((faker) => faker.person.fullName())
|
|
286
|
-
name: string;
|
|
287
|
-
|
|
288
|
-
@Factory((faker) => faker.internet.email())
|
|
289
|
-
email: string;
|
|
290
|
-
|
|
291
|
-
@Factory((faker) => faker.datatype.number({ min: 18, max: 80 }))
|
|
292
|
-
age: number;
|
|
293
|
-
}
|
|
70
|
+
})
|
|
71
|
+
export class AppModule {}
|
|
294
72
|
```
|
|
295
73
|
|
|
296
|
-
###
|
|
74
|
+
### 2. Create a Template
|
|
297
75
|
|
|
298
|
-
|
|
299
|
-
import { DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
300
|
-
import { UserFactory } from './user.factory';
|
|
301
|
-
|
|
302
|
-
// Create factory
|
|
303
|
-
const factory = DataFactory.createForClass(UserFactory);
|
|
304
|
-
|
|
305
|
-
// Generate one object
|
|
306
|
-
const user = factory.generate(1)[0];
|
|
307
|
-
|
|
308
|
-
// Generate multiple objects
|
|
309
|
-
const users = factory.generate(10);
|
|
310
|
-
|
|
311
|
-
// Generate with overrides
|
|
312
|
-
const admin = factory.generate(1, { role: 'admin' })[0];
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Factory with Relationships
|
|
316
|
-
|
|
317
|
-
```typescript
|
|
318
|
-
import { Factory } from '@ackplus/nest-dynamic-templates';
|
|
319
|
-
|
|
320
|
-
export class PostFactory {
|
|
321
|
-
@Factory((faker) => faker.lorem.sentence())
|
|
322
|
-
title: string;
|
|
323
|
-
|
|
324
|
-
@Factory((faker) => faker.lorem.paragraphs(3))
|
|
325
|
-
content: string;
|
|
326
|
-
|
|
327
|
-
// Will be set manually in seeder
|
|
328
|
-
authorId: number;
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
## ๐ฑ Seeders
|
|
333
|
-
|
|
334
|
-
### Basic Seeder
|
|
76
|
+
You can create templates programmatically using the `TemplateService`.
|
|
335
77
|
|
|
336
78
|
```typescript
|
|
337
79
|
import { Injectable } from '@nestjs/common';
|
|
338
|
-
import {
|
|
339
|
-
import { Repository } from 'typeorm';
|
|
340
|
-
import { Seeder, DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
341
|
-
import { User } from '../entities/user.entity';
|
|
342
|
-
import { UserFactory } from '../factories/user.factory';
|
|
80
|
+
import { TemplateService, TemplateEngineEnum, TemplateLanguageEnum } from '@ackplus/nest-dynamic-templates';
|
|
343
81
|
|
|
344
82
|
@Injectable()
|
|
345
|
-
export class
|
|
346
|
-
constructor(
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
83
|
+
export class MyService {
|
|
84
|
+
constructor(private readonly templateService: TemplateService) {}
|
|
85
|
+
|
|
86
|
+
async createWelcomeTemplate() {
|
|
87
|
+
await this.templateService.createTemplate({
|
|
88
|
+
name: 'welcome-email',
|
|
89
|
+
scope: 'system', // 'system' or custom scope
|
|
90
|
+
locale: 'en',
|
|
91
|
+
subject: 'Welcome, {{ name }}!',
|
|
92
|
+
content: '<h1>Hello {{ name }}</h1><p>Welcome to our platform.</p>',
|
|
93
|
+
engine: TemplateEngineEnum.NUNJUCKS,
|
|
94
|
+
language: TemplateLanguageEnum.HTML,
|
|
95
|
+
type: 'email',
|
|
96
|
+
});
|
|
359
97
|
}
|
|
360
98
|
}
|
|
361
99
|
```
|
|
362
100
|
|
|
363
|
-
###
|
|
364
|
-
|
|
365
|
-
```typescript
|
|
366
|
-
import { Injectable } from '@nestjs/common';
|
|
367
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
368
|
-
import { Repository } from 'typeorm';
|
|
369
|
-
import { Seeder, DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
370
|
-
import { User } from '../entities/user.entity';
|
|
371
|
-
import { Post } from '../entities/post.entity';
|
|
372
|
-
import { UserFactory } from '../factories/user.factory';
|
|
373
|
-
import { PostFactory } from '../factories/post.factory';
|
|
374
|
-
|
|
375
|
-
@Injectable()
|
|
376
|
-
export class PostSeeder implements Seeder {
|
|
377
|
-
constructor(
|
|
378
|
-
@InjectRepository(User)
|
|
379
|
-
private readonly userRepository: Repository<User>,
|
|
380
|
-
@InjectRepository(Post)
|
|
381
|
-
private readonly postRepository: Repository<Post>,
|
|
382
|
-
) {}
|
|
383
|
-
|
|
384
|
-
async seed(): Promise<void> {
|
|
385
|
-
// Get existing users
|
|
386
|
-
const users = await this.userRepository.find();
|
|
387
|
-
|
|
388
|
-
if (users.length === 0) {
|
|
389
|
-
console.log('โ ๏ธ No users found. Run UserSeeder first.');
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Create posts for each user
|
|
394
|
-
const postFactory = DataFactory.createForClass(PostFactory);
|
|
395
|
-
|
|
396
|
-
for (const user of users) {
|
|
397
|
-
// Generate 3 posts per user
|
|
398
|
-
const posts = postFactory.generate(3).map(post => ({
|
|
399
|
-
...post,
|
|
400
|
-
author: user,
|
|
401
|
-
}));
|
|
402
|
-
|
|
403
|
-
await this.postRepository.save(posts);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
console.log(`โ
Seeded ${users.length * 3} posts`);
|
|
407
|
-
}
|
|
101
|
+
### 3. Render a Template
|
|
408
102
|
|
|
409
|
-
|
|
410
|
-
await this.postRepository.delete({});
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### Conditional Seeding
|
|
103
|
+
Render a stored template by name.
|
|
416
104
|
|
|
417
105
|
```typescript
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const count = options?.dummyData ? 100 : 10;
|
|
428
|
-
const users = factory.generate(count);
|
|
429
|
-
|
|
430
|
-
await this.userRepository.save(users);
|
|
431
|
-
console.log(`โ
Seeded ${count} users`);
|
|
432
|
-
}
|
|
106
|
+
async renderEmail(userName: string) {
|
|
107
|
+
const result = await this.templateService.render({
|
|
108
|
+
name: 'welcome-email',
|
|
109
|
+
scope: 'system',
|
|
110
|
+
locale: 'en',
|
|
111
|
+
context: {
|
|
112
|
+
name: userName,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
433
115
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
116
|
+
console.log(result.subject); // "Welcome, John!"
|
|
117
|
+
console.log(result.content); // "<h1>Hello John</h1><p>Welcome to our platform.</p>"
|
|
437
118
|
}
|
|
438
119
|
```
|
|
439
120
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
```bash
|
|
443
|
-
nest-seed -c seeder.config.ts --dummyData
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
### MongoDB/Mongoose Seeder
|
|
447
|
-
|
|
448
|
-
```typescript
|
|
449
|
-
import { Injectable } from '@nestjs/common';
|
|
450
|
-
import { InjectModel } from '@nestjs/mongoose';
|
|
451
|
-
import { Model } from 'mongoose';
|
|
452
|
-
import { Seeder, DataFactory } from '@ackplus/nest-dynamic-templates';
|
|
453
|
-
import { User } from '../schemas/user.schema';
|
|
454
|
-
import { UserFactory } from '../factories/user.factory';
|
|
455
|
-
|
|
456
|
-
@Injectable()
|
|
457
|
-
export class UserSeeder implements Seeder {
|
|
458
|
-
constructor(
|
|
459
|
-
@InjectModel(User.name)
|
|
460
|
-
private readonly userModel: Model<User>,
|
|
461
|
-
) {}
|
|
462
|
-
|
|
463
|
-
async seed(): Promise<void> {
|
|
464
|
-
const factory = DataFactory.createForClass(UserFactory);
|
|
465
|
-
const users = factory.generate(10);
|
|
466
|
-
await this.userModel.insertMany(users);
|
|
467
|
-
}
|
|
121
|
+
## ๐ API Reference
|
|
468
122
|
|
|
469
|
-
|
|
470
|
-
await this.userModel.deleteMany({});
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
```
|
|
123
|
+
### TemplateService
|
|
474
124
|
|
|
475
|
-
|
|
125
|
+
The main service for managing and rendering templates.
|
|
476
126
|
|
|
477
|
-
|
|
127
|
+
#### `render(options: RenderTemplateDto)`
|
|
128
|
+
Renders a template stored in the database.
|
|
478
129
|
|
|
479
130
|
```typescript
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
TypeOrmModule.forFeature([User]),
|
|
487
|
-
],
|
|
488
|
-
seeders: [UserSeeder],
|
|
489
|
-
providers: [CustomService], // Inject custom services
|
|
490
|
-
};
|
|
131
|
+
const output = await templateService.render({
|
|
132
|
+
name: 'my-template',
|
|
133
|
+
scope: 'system',
|
|
134
|
+
locale: 'en',
|
|
135
|
+
context: { foo: 'bar' },
|
|
136
|
+
});
|
|
491
137
|
```
|
|
492
138
|
|
|
493
|
-
|
|
139
|
+
#### `renderContent(options: RenderContentTemplateDto)`
|
|
140
|
+
Renders raw content string directly without fetching from the database.
|
|
494
141
|
|
|
495
142
|
```typescript
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
export default {
|
|
503
|
-
imports: [
|
|
504
|
-
TypeOrmModule.forRoot({
|
|
505
|
-
type: 'postgres',
|
|
506
|
-
host: process.env.DB_HOST,
|
|
507
|
-
database: isDev ? 'mydb_dev' : 'mydb_prod',
|
|
508
|
-
synchronize: isDev,
|
|
509
|
-
}),
|
|
510
|
-
TypeOrmModule.forFeature([User, Post]),
|
|
511
|
-
],
|
|
512
|
-
seeders: isDev
|
|
513
|
-
? [UserSeeder, PostSeeder, TestDataSeeder]
|
|
514
|
-
: [UserSeeder, PostSeeder],
|
|
515
|
-
};
|
|
143
|
+
const html = await templateService.renderContent({
|
|
144
|
+
content: 'Hello {{ name }}',
|
|
145
|
+
engine: TemplateEngineEnum.NUNJUCKS,
|
|
146
|
+
context: { name: 'World' },
|
|
147
|
+
});
|
|
516
148
|
```
|
|
517
149
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
```typescript
|
|
521
|
-
@Injectable()
|
|
522
|
-
export class UserSeeder implements Seeder {
|
|
523
|
-
async seed(): Promise<void> {
|
|
524
|
-
const factory = DataFactory.createForClass(UserFactory);
|
|
525
|
-
const batchSize = 1000;
|
|
526
|
-
const totalRecords = 10000;
|
|
527
|
-
|
|
528
|
-
for (let i = 0; i < totalRecords; i += batchSize) {
|
|
529
|
-
const users = factory.generate(batchSize);
|
|
530
|
-
await this.userRepository.save(users);
|
|
531
|
-
console.log(`โ
Seeded ${Math.min(i + batchSize, totalRecords)}/${totalRecords} users`);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
async drop(): Promise<void> {
|
|
536
|
-
await this.userRepository.delete({});
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
```
|
|
150
|
+
#### `createTemplate(data: CreateTemplateDto)`
|
|
151
|
+
Creates a new system template.
|
|
540
152
|
|
|
541
|
-
|
|
153
|
+
#### `updateTemplate(id: string, updates: Partial<CreateTemplateDto>)`
|
|
154
|
+
Updates an existing template. If you try to update a `system` template without permission, it may create a scoped override instead.
|
|
542
155
|
|
|
543
|
-
###
|
|
156
|
+
### TemplateLayoutService
|
|
544
157
|
|
|
545
|
-
|
|
546
|
-
class DataFactory {
|
|
547
|
-
// Create factory for a class
|
|
548
|
-
static createForClass<T>(factoryClass: new () => T): DataFactory<T>
|
|
549
|
-
|
|
550
|
-
// Generate instances
|
|
551
|
-
generate(count: number, override?: Partial<T>): T[]
|
|
552
|
-
}
|
|
553
|
-
```
|
|
158
|
+
Manage reusable layouts (e.g., email wrappers with header/footer).
|
|
554
159
|
|
|
555
|
-
|
|
160
|
+
#### `createLayout(data: CreateTemplateLayoutDto)`
|
|
161
|
+
Create a new layout.
|
|
556
162
|
|
|
557
163
|
```typescript
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
drop(options?: SeederServiceOptions): Promise<void>
|
|
564
|
-
}
|
|
164
|
+
await layoutService.createLayout({
|
|
165
|
+
name: 'main-layout',
|
|
166
|
+
content: '<html><body>{{ content }}</body></html>', // {{ content }} is the placeholder
|
|
167
|
+
engine: TemplateEngineEnum.NUNJUCKS,
|
|
168
|
+
});
|
|
565
169
|
```
|
|
566
170
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
```typescript
|
|
570
|
-
// Simple factory
|
|
571
|
-
@Factory((faker) => faker.person.fullName())
|
|
572
|
-
name: string;
|
|
573
|
-
|
|
574
|
-
// With options
|
|
575
|
-
@Factory((faker) => faker.datatype.number({ min: 1, max: 100 }))
|
|
576
|
-
age: number;
|
|
577
|
-
|
|
578
|
-
// Array values
|
|
579
|
-
@Factory((faker) => faker.helpers.arrayElement(['admin', 'user']))
|
|
580
|
-
role: string;
|
|
581
|
-
```
|
|
171
|
+
## โ๏ธ Configuration Options
|
|
582
172
|
|
|
583
|
-
|
|
173
|
+
When importing the module, you can configure the enabled engines:
|
|
584
174
|
|
|
585
175
|
```typescript
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
176
|
+
NestDynamicTemplatesModule.forRoot({
|
|
177
|
+
engines: {
|
|
178
|
+
// Template Logic Engines
|
|
179
|
+
template: [
|
|
180
|
+
TemplateEngineEnum.NUNJUCKS,
|
|
181
|
+
TemplateEngineEnum.HANDLEBARS,
|
|
182
|
+
TemplateEngineEnum.EJS,
|
|
183
|
+
TemplateEngineEnum.PUG
|
|
184
|
+
],
|
|
185
|
+
// Output Language Processors
|
|
186
|
+
language: [
|
|
187
|
+
TemplateLanguageEnum.HTML,
|
|
188
|
+
TemplateLanguageEnum.MJML,
|
|
189
|
+
TemplateLanguageEnum.TEXT,
|
|
190
|
+
TemplateLanguageEnum.MARKDOWN
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
})
|
|
591
194
|
```
|
|
592
195
|
|
|
593
|
-
## ๐ค Contributing
|
|
594
|
-
|
|
595
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
596
|
-
|
|
597
196
|
## ๐ License
|
|
598
197
|
|
|
599
198
|
This project is licensed under the MIT License.
|
|
600
|
-
|
|
601
|
-
## ๐ Acknowledgments
|
|
602
|
-
|
|
603
|
-
- Built with [NestJS](https://nestjs.com/)
|
|
604
|
-
- Powered by [Faker.js](https://fakerjs.dev/)
|
|
605
|
-
- Inspired by database seeding patterns from Laravel and other frameworks
|
|
606
|
-
|
|
607
|
-
## ๐ฎ Support
|
|
608
|
-
|
|
609
|
-
If you have any questions or need help:
|
|
610
|
-
- Open an issue on [GitHub](https://github.com/ackplus/nest-dynamic-templates/issues)
|
|
611
|
-
- Check the [examples](./examples/) directory
|
|
612
|
-
- Review the [Quick Start Guide](./QUICKSTART.md)
|
|
613
|
-
|
|
614
|
-
---
|
|
615
|
-
|
|
616
|
-
Made with โค๏ธ for the NestJS community
|