@objectql/platform-node 1.6.0
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/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/dist/driver.d.ts +2 -0
- package/dist/driver.js +55 -0
- package/dist/driver.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +12 -0
- package/dist/loader.js +358 -0
- package/dist/loader.js.map +1 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +56 -0
- package/dist/plugin.js.map +1 -0
- package/jest.config.js +13 -0
- package/package.json +19 -0
- package/src/driver.ts +54 -0
- package/src/index.ts +3 -0
- package/src/loader.ts +349 -0
- package/src/plugin.ts +53 -0
- package/test/dynamic.test.ts +33 -0
- package/test/fixtures/project-with-validation.object.yml +124 -0
- package/test/fixtures/project.action.js +8 -0
- package/test/fixtures/project.object.yml +41 -0
- package/test/fixtures/test_dashboard.page.yml +42 -0
- package/test/fixtures/test_page.page.yml +54 -0
- package/test/fixtures/test_responsive.page.yml +39 -0
- package/test/fixtures/test_sections.page.yml +45 -0
- package/test/loader.test.ts +15 -0
- package/test/metadata.test.ts +49 -0
- package/test/page.test.ts +137 -0
- package/test/validation.test.ts +486 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { Validator } from '@objectql/core';
|
|
2
|
+
import {
|
|
3
|
+
ValidationContext,
|
|
4
|
+
AnyValidationRule,
|
|
5
|
+
CrossFieldValidationRule,
|
|
6
|
+
StateMachineValidationRule,
|
|
7
|
+
FieldConfig,
|
|
8
|
+
} from '@objectql/types';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as yaml from 'js-yaml';
|
|
12
|
+
|
|
13
|
+
describe('Validation System', () => {
|
|
14
|
+
let validator: Validator;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
validator = new Validator();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('Field-level validation', () => {
|
|
21
|
+
it('should validate required fields', async () => {
|
|
22
|
+
const fieldConfig: FieldConfig = {
|
|
23
|
+
type: 'text',
|
|
24
|
+
label: 'Name',
|
|
25
|
+
required: true,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const context: ValidationContext = {
|
|
29
|
+
record: { name: '' },
|
|
30
|
+
operation: 'create',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const results = await validator.validateField('name', fieldConfig, '', context);
|
|
34
|
+
|
|
35
|
+
expect(results).toHaveLength(1);
|
|
36
|
+
expect(results[0].valid).toBe(false);
|
|
37
|
+
expect(results[0].message).toContain('required');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should validate email format', async () => {
|
|
41
|
+
const fieldConfig: FieldConfig = {
|
|
42
|
+
type: 'email',
|
|
43
|
+
validation: {
|
|
44
|
+
format: 'email',
|
|
45
|
+
message: 'Invalid email',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const context: ValidationContext = {
|
|
50
|
+
record: { email: 'invalid-email' },
|
|
51
|
+
operation: 'create',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const results = await validator.validateField('email', fieldConfig, 'invalid-email', context);
|
|
55
|
+
|
|
56
|
+
expect(results).toHaveLength(1);
|
|
57
|
+
expect(results[0].valid).toBe(false);
|
|
58
|
+
expect(results[0].message).toBe('Invalid email');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should validate valid email format', async () => {
|
|
62
|
+
const fieldConfig: FieldConfig = {
|
|
63
|
+
type: 'email',
|
|
64
|
+
validation: {
|
|
65
|
+
format: 'email',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const context: ValidationContext = {
|
|
70
|
+
record: { email: 'test@example.com' },
|
|
71
|
+
operation: 'create',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const results = await validator.validateField('email', fieldConfig, 'test@example.com', context);
|
|
75
|
+
|
|
76
|
+
expect(results).toHaveLength(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should validate URL format', async () => {
|
|
80
|
+
const fieldConfig: FieldConfig = {
|
|
81
|
+
type: 'url',
|
|
82
|
+
validation: {
|
|
83
|
+
format: 'url',
|
|
84
|
+
protocols: ['http', 'https'],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const context: ValidationContext = {
|
|
89
|
+
record: { website: 'not-a-url' },
|
|
90
|
+
operation: 'create',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const results = await validator.validateField('website', fieldConfig, 'not-a-url', context);
|
|
94
|
+
|
|
95
|
+
expect(results.length).toBeGreaterThan(0);
|
|
96
|
+
expect(results[0].valid).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should validate min/max values', async () => {
|
|
100
|
+
const fieldConfig: FieldConfig = {
|
|
101
|
+
type: 'number',
|
|
102
|
+
validation: {
|
|
103
|
+
min: 0,
|
|
104
|
+
max: 100,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const context: ValidationContext = {
|
|
109
|
+
record: { age: 150 },
|
|
110
|
+
operation: 'create',
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const results = await validator.validateField('age', fieldConfig, 150, context);
|
|
114
|
+
|
|
115
|
+
expect(results).toHaveLength(1);
|
|
116
|
+
expect(results[0].valid).toBe(false);
|
|
117
|
+
expect(results[0].message).toContain('100');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should validate string length', async () => {
|
|
121
|
+
const fieldConfig: FieldConfig = {
|
|
122
|
+
type: 'text',
|
|
123
|
+
validation: {
|
|
124
|
+
min_length: 3,
|
|
125
|
+
max_length: 10,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const context: ValidationContext = {
|
|
130
|
+
record: { username: 'ab' },
|
|
131
|
+
operation: 'create',
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const results = await validator.validateField('username', fieldConfig, 'ab', context);
|
|
135
|
+
|
|
136
|
+
expect(results).toHaveLength(1);
|
|
137
|
+
expect(results[0].valid).toBe(false);
|
|
138
|
+
expect(results[0].message).toContain('3');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should validate regex pattern', async () => {
|
|
142
|
+
const fieldConfig: FieldConfig = {
|
|
143
|
+
type: 'text',
|
|
144
|
+
validation: {
|
|
145
|
+
pattern: '^[a-zA-Z0-9_]+$',
|
|
146
|
+
message: 'Username must be alphanumeric',
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const context: ValidationContext = {
|
|
151
|
+
record: { username: 'user@123' },
|
|
152
|
+
operation: 'create',
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const results = await validator.validateField('username', fieldConfig, 'user@123', context);
|
|
156
|
+
|
|
157
|
+
expect(results).toHaveLength(1);
|
|
158
|
+
expect(results[0].valid).toBe(false);
|
|
159
|
+
expect(results[0].message).toBe('Username must be alphanumeric');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should handle invalid regex pattern gracefully', async () => {
|
|
163
|
+
const fieldConfig: FieldConfig = {
|
|
164
|
+
type: 'text',
|
|
165
|
+
validation: {
|
|
166
|
+
pattern: '[invalid(regex', // Invalid regex
|
|
167
|
+
message: 'Should not see this',
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const context: ValidationContext = {
|
|
172
|
+
record: { username: 'test' },
|
|
173
|
+
operation: 'create',
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const results = await validator.validateField('username', fieldConfig, 'test', context);
|
|
177
|
+
|
|
178
|
+
expect(results).toHaveLength(1);
|
|
179
|
+
expect(results[0].valid).toBe(false);
|
|
180
|
+
expect(results[0].message).toContain('Invalid regex pattern');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('Cross-field validation', () => {
|
|
185
|
+
it('should validate date range with compare_to', async () => {
|
|
186
|
+
const rule: CrossFieldValidationRule = {
|
|
187
|
+
name: 'valid_date_range',
|
|
188
|
+
type: 'cross_field',
|
|
189
|
+
rule: {
|
|
190
|
+
field: 'end_date',
|
|
191
|
+
operator: '>=',
|
|
192
|
+
compare_to: 'start_date',
|
|
193
|
+
},
|
|
194
|
+
message: 'End date must be on or after start date',
|
|
195
|
+
error_code: 'INVALID_DATE_RANGE',
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const context: ValidationContext = {
|
|
199
|
+
record: {
|
|
200
|
+
start_date: '2024-01-01',
|
|
201
|
+
end_date: '2023-12-31', // Before start date
|
|
202
|
+
},
|
|
203
|
+
operation: 'create',
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const result = await validator.validate([rule], context);
|
|
207
|
+
|
|
208
|
+
expect(result.valid).toBe(false);
|
|
209
|
+
expect(result.errors).toHaveLength(1);
|
|
210
|
+
expect(result.errors[0].error_code).toBe('INVALID_DATE_RANGE');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should pass valid date range with compare_to', async () => {
|
|
214
|
+
const rule: CrossFieldValidationRule = {
|
|
215
|
+
name: 'valid_date_range',
|
|
216
|
+
type: 'cross_field',
|
|
217
|
+
rule: {
|
|
218
|
+
field: 'end_date',
|
|
219
|
+
operator: '>=',
|
|
220
|
+
compare_to: 'start_date',
|
|
221
|
+
},
|
|
222
|
+
message: 'End date must be on or after start date',
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const context: ValidationContext = {
|
|
226
|
+
record: {
|
|
227
|
+
start_date: '2024-01-01',
|
|
228
|
+
end_date: '2024-02-01', // After start date
|
|
229
|
+
},
|
|
230
|
+
operation: 'create',
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const result = await validator.validate([rule], context);
|
|
234
|
+
|
|
235
|
+
expect(result.valid).toBe(true);
|
|
236
|
+
expect(result.errors).toHaveLength(0);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should validate with fixed value comparison', async () => {
|
|
240
|
+
const rule: CrossFieldValidationRule = {
|
|
241
|
+
name: 'min_value_check',
|
|
242
|
+
type: 'cross_field',
|
|
243
|
+
rule: {
|
|
244
|
+
field: 'budget',
|
|
245
|
+
operator: '>=',
|
|
246
|
+
value: 1000,
|
|
247
|
+
},
|
|
248
|
+
message: 'Budget must be at least 1000',
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const context: ValidationContext = {
|
|
252
|
+
record: {
|
|
253
|
+
budget: 500,
|
|
254
|
+
},
|
|
255
|
+
operation: 'create',
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const result = await validator.validate([rule], context);
|
|
259
|
+
|
|
260
|
+
expect(result.valid).toBe(false);
|
|
261
|
+
expect(result.errors).toHaveLength(1);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
describe('State machine validation', () => {
|
|
266
|
+
it('should validate allowed state transitions', async () => {
|
|
267
|
+
const rule: StateMachineValidationRule = {
|
|
268
|
+
name: 'status_transition',
|
|
269
|
+
type: 'state_machine',
|
|
270
|
+
field: 'status',
|
|
271
|
+
transitions: {
|
|
272
|
+
planning: {
|
|
273
|
+
allowed_next: ['active', 'cancelled'],
|
|
274
|
+
},
|
|
275
|
+
active: {
|
|
276
|
+
allowed_next: ['on_hold', 'completed', 'cancelled'],
|
|
277
|
+
},
|
|
278
|
+
completed: {
|
|
279
|
+
allowed_next: [],
|
|
280
|
+
is_terminal: true,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
message: 'Invalid status transition from {{old_status}} to {{new_status}}',
|
|
284
|
+
error_code: 'INVALID_STATE_TRANSITION',
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const context: ValidationContext = {
|
|
288
|
+
record: { status: 'active' },
|
|
289
|
+
previousRecord: { status: 'planning' },
|
|
290
|
+
operation: 'update',
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const result = await validator.validate([rule], context);
|
|
294
|
+
|
|
295
|
+
expect(result.valid).toBe(true);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should reject invalid state transitions', async () => {
|
|
299
|
+
const rule: StateMachineValidationRule = {
|
|
300
|
+
name: 'status_transition',
|
|
301
|
+
type: 'state_machine',
|
|
302
|
+
field: 'status',
|
|
303
|
+
transitions: {
|
|
304
|
+
completed: {
|
|
305
|
+
allowed_next: [],
|
|
306
|
+
is_terminal: true,
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
message: 'Invalid status transition from {{old_status}} to {{new_status}}',
|
|
310
|
+
error_code: 'INVALID_STATE_TRANSITION',
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const context: ValidationContext = {
|
|
314
|
+
record: { status: 'active' },
|
|
315
|
+
previousRecord: { status: 'completed' },
|
|
316
|
+
operation: 'update',
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const result = await validator.validate([rule], context);
|
|
320
|
+
|
|
321
|
+
expect(result.valid).toBe(false);
|
|
322
|
+
expect(result.errors).toHaveLength(1);
|
|
323
|
+
expect(result.errors[0].message).toContain('completed');
|
|
324
|
+
expect(result.errors[0].message).toContain('active');
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it('should allow same state (no transition)', async () => {
|
|
328
|
+
const rule: StateMachineValidationRule = {
|
|
329
|
+
name: 'status_transition',
|
|
330
|
+
type: 'state_machine',
|
|
331
|
+
field: 'status',
|
|
332
|
+
transitions: {
|
|
333
|
+
completed: {
|
|
334
|
+
allowed_next: [],
|
|
335
|
+
is_terminal: true,
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
message: 'Invalid status transition',
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const context: ValidationContext = {
|
|
342
|
+
record: { status: 'completed' },
|
|
343
|
+
previousRecord: { status: 'completed' },
|
|
344
|
+
operation: 'update',
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const result = await validator.validate([rule], context);
|
|
348
|
+
|
|
349
|
+
expect(result.valid).toBe(true);
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
describe('Validation with triggers', () => {
|
|
354
|
+
it('should only run validation on specified triggers', async () => {
|
|
355
|
+
const rule: AnyValidationRule = {
|
|
356
|
+
name: 'create_only',
|
|
357
|
+
type: 'cross_field',
|
|
358
|
+
trigger: ['create'],
|
|
359
|
+
rule: {
|
|
360
|
+
field: 'name',
|
|
361
|
+
operator: '!=',
|
|
362
|
+
value: null,
|
|
363
|
+
},
|
|
364
|
+
message: 'Name is required',
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// Should run on create
|
|
368
|
+
const createContext: ValidationContext = {
|
|
369
|
+
record: { name: null },
|
|
370
|
+
operation: 'create',
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const createResult = await validator.validate([rule], createContext);
|
|
374
|
+
expect(createResult.valid).toBe(false);
|
|
375
|
+
|
|
376
|
+
// Should not run on update
|
|
377
|
+
const updateContext: ValidationContext = {
|
|
378
|
+
record: { name: null },
|
|
379
|
+
operation: 'update',
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
const updateResult = await validator.validate([rule], updateContext);
|
|
383
|
+
expect(updateResult.valid).toBe(true); // Rule not applied
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('should only run validation when specific fields change', async () => {
|
|
387
|
+
const rule: AnyValidationRule = {
|
|
388
|
+
name: 'budget_check',
|
|
389
|
+
type: 'cross_field',
|
|
390
|
+
fields: ['budget'],
|
|
391
|
+
rule: {
|
|
392
|
+
field: 'budget',
|
|
393
|
+
operator: '<=',
|
|
394
|
+
value: 1000000,
|
|
395
|
+
},
|
|
396
|
+
message: 'Budget too high',
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
// Should run when budget changes
|
|
400
|
+
const withBudgetChange: ValidationContext = {
|
|
401
|
+
record: { budget: 2000000 },
|
|
402
|
+
operation: 'update',
|
|
403
|
+
changedFields: ['budget', 'name'],
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const budgetResult = await validator.validate([rule], withBudgetChange);
|
|
407
|
+
expect(budgetResult.valid).toBe(false);
|
|
408
|
+
|
|
409
|
+
// Should not run when budget doesn't change
|
|
410
|
+
const withoutBudgetChange: ValidationContext = {
|
|
411
|
+
record: { budget: 2000000 },
|
|
412
|
+
operation: 'update',
|
|
413
|
+
changedFields: ['name', 'description'],
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const noBudgetResult = await validator.validate([rule], withoutBudgetChange);
|
|
417
|
+
expect(noBudgetResult.valid).toBe(true); // Rule not applied
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('Load validation from YAML fixture', () => {
|
|
422
|
+
it('should load and parse validation rules from YAML', () => {
|
|
423
|
+
const yamlPath = path.join(__dirname, 'fixtures', 'project-with-validation.object.yml');
|
|
424
|
+
const fileContents = fs.readFileSync(yamlPath, 'utf8');
|
|
425
|
+
const objectDef = yaml.load(fileContents) as any;
|
|
426
|
+
|
|
427
|
+
expect(objectDef.validation).toBeDefined();
|
|
428
|
+
expect(objectDef.validation.rules).toBeDefined();
|
|
429
|
+
expect(objectDef.validation.rules.length).toBeGreaterThan(0);
|
|
430
|
+
|
|
431
|
+
// Check cross-field rule
|
|
432
|
+
const dateRangeRule = objectDef.validation.rules.find((r: any) => r.name === 'valid_date_range');
|
|
433
|
+
expect(dateRangeRule).toBeDefined();
|
|
434
|
+
expect(dateRangeRule.type).toBe('cross_field');
|
|
435
|
+
expect(dateRangeRule.error_code).toBe('INVALID_DATE_RANGE');
|
|
436
|
+
|
|
437
|
+
// Check state machine rule
|
|
438
|
+
const statusRule = objectDef.validation.rules.find((r: any) => r.name === 'status_transition');
|
|
439
|
+
expect(statusRule).toBeDefined();
|
|
440
|
+
expect(statusRule.type).toBe('state_machine');
|
|
441
|
+
expect(statusRule.field).toBe('status');
|
|
442
|
+
expect(statusRule.transitions).toBeDefined();
|
|
443
|
+
expect(statusRule.transitions.planning.allowed_next).toContain('active');
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
describe('Severity levels', () => {
|
|
448
|
+
it('should categorize errors by severity', async () => {
|
|
449
|
+
const rules: AnyValidationRule[] = [
|
|
450
|
+
{
|
|
451
|
+
name: 'error_rule',
|
|
452
|
+
type: 'cross_field',
|
|
453
|
+
severity: 'error',
|
|
454
|
+
rule: { field: 'x', operator: '=', value: 1 },
|
|
455
|
+
message: 'Error',
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
name: 'warning_rule',
|
|
459
|
+
type: 'cross_field',
|
|
460
|
+
severity: 'warning',
|
|
461
|
+
rule: { field: 'y', operator: '=', value: 1 },
|
|
462
|
+
message: 'Warning',
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: 'info_rule',
|
|
466
|
+
type: 'cross_field',
|
|
467
|
+
severity: 'info',
|
|
468
|
+
rule: { field: 'z', operator: '=', value: 1 },
|
|
469
|
+
message: 'Info',
|
|
470
|
+
},
|
|
471
|
+
];
|
|
472
|
+
|
|
473
|
+
const context: ValidationContext = {
|
|
474
|
+
record: { x: 2, y: 2, z: 2 }, // All fail
|
|
475
|
+
operation: 'create',
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
const result = await validator.validate(rules, context);
|
|
479
|
+
|
|
480
|
+
expect(result.errors).toHaveLength(1);
|
|
481
|
+
expect(result.warnings).toHaveLength(1);
|
|
482
|
+
expect(result.info).toHaveLength(1);
|
|
483
|
+
expect(result.valid).toBe(false); // Errors make it invalid
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "dist",
|
|
5
|
+
"rootDir": "src"
|
|
6
|
+
},
|
|
7
|
+
"include": ["src/**/*"],
|
|
8
|
+
"references": [
|
|
9
|
+
{ "path": "../types" },
|
|
10
|
+
{ "path": "../core" },
|
|
11
|
+
{ "path": "../../drivers/sql" },
|
|
12
|
+
{ "path": "../../drivers/mongo" }
|
|
13
|
+
]
|
|
14
|
+
}
|