@5minds/node-red-contrib-processcube-tools 1.2.0-develop-d19f89-mg68thdf → 1.2.0-develop-59ef22-mg9d9ja5

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 (55) hide show
  1. package/.mocharc.json +5 -0
  2. package/package.json +26 -10
  3. package/src/custom-node-template/custom-node-template.html.template +45 -0
  4. package/src/custom-node-template/custom-node-template.ts.template +69 -0
  5. package/src/email-receiver/email-receiver.ts +439 -0
  6. package/src/email-sender/email-sender.ts +210 -0
  7. package/{processcube-html-to-text/processcube-html-to-text.html → src/html-to-text/html-to-text.html} +3 -3
  8. package/src/html-to-text/html-to-text.ts +53 -0
  9. package/src/index.ts +12 -0
  10. package/src/interfaces/EmailReceiverMessage.ts +22 -0
  11. package/src/interfaces/EmailSenderNodeProperties.ts +37 -0
  12. package/src/interfaces/FetchState.ts +9 -0
  13. package/src/interfaces/ImapConnectionConfig.ts +14 -0
  14. package/src/test/framework/advanced-test-patterns.ts +224 -0
  15. package/src/test/framework/generic-node-test-suite.ts +58 -0
  16. package/src/test/framework/index.ts +17 -0
  17. package/src/test/framework/integration-assertions.ts +67 -0
  18. package/src/test/framework/integration-scenario-builder.ts +77 -0
  19. package/src/test/framework/integration-test-runner.ts +101 -0
  20. package/src/test/framework/node-assertions.ts +63 -0
  21. package/src/test/framework/node-test-runner.ts +260 -0
  22. package/src/test/framework/test-scenario-builder.ts +74 -0
  23. package/src/test/framework/types.ts +61 -0
  24. package/src/test/helpers/email-receiver-test-configs.ts +67 -0
  25. package/src/test/helpers/email-receiver-test-flows.ts +16 -0
  26. package/src/test/helpers/email-sender-test-configs.ts +123 -0
  27. package/src/test/helpers/email-sender-test-flows.ts +16 -0
  28. package/src/test/integration/email-receiver.integration.test.ts +41 -0
  29. package/src/test/integration/email-sender.integration.test.ts +129 -0
  30. package/src/test/interfaces/email-data.ts +10 -0
  31. package/src/test/interfaces/email-receiver-config.ts +12 -0
  32. package/src/test/interfaces/email-sender-config.ts +26 -0
  33. package/src/test/interfaces/imap-config.ts +9 -0
  34. package/src/test/interfaces/imap-mailbox.ts +5 -0
  35. package/src/test/interfaces/mail-options.ts +20 -0
  36. package/src/test/interfaces/parsed-email.ts +11 -0
  37. package/src/test/interfaces/send-mail-result.ts +7 -0
  38. package/src/test/mocks/imap-mock.ts +147 -0
  39. package/src/test/mocks/mailparser-mock.ts +82 -0
  40. package/src/test/mocks/nodemailer-mock.ts +118 -0
  41. package/src/test/unit/email-receiver.unit.test.ts +471 -0
  42. package/src/test/unit/email-sender.unit.test.ts +550 -0
  43. package/tsconfig.json +23 -0
  44. package/email-receiver/email-receiver.js +0 -304
  45. package/email-sender/email-sender.js +0 -178
  46. package/examples/.gitkeep +0 -0
  47. package/processcube-html-to-text/processcube-html-to-text.js +0 -22
  48. package/test/helpers/email-receiver.mocks.js +0 -447
  49. package/test/helpers/email-sender.mocks.js +0 -368
  50. package/test/integration/email-receiver.integration.test.js +0 -515
  51. package/test/integration/email-sender.integration.test.js +0 -239
  52. package/test/unit/email-receiver.unit.test.js +0 -304
  53. package/test/unit/email-sender.unit.test.js +0 -570
  54. /package/{email-receiver → src/email-receiver}/email-receiver.html +0 -0
  55. /package/{email-sender → src/email-sender}/email-sender.html +0 -0
@@ -0,0 +1,550 @@
1
+ import { expect } from 'chai';
2
+ import emailSenderNode from '../../email-sender/email-sender';
3
+ import { EmailSenderTestConfigs } from '../helpers/email-sender-test-configs';
4
+
5
+ import { createMockNodemailer, withNodemailerMock } from '../mocks/nodemailer-mock';
6
+
7
+ import {
8
+ TestScenarioBuilder,
9
+ NodeTestRunner,
10
+ NodeAssertions,
11
+ createNodeTestSuite,
12
+ ErrorResilienceTestBuilder,
13
+ EdgeCaseTestBuilder,
14
+ type TestScenario,
15
+ MockNodeREDOptions,
16
+ } from '../framework';
17
+
18
+ describe('E-Mail Sender Node - Unit Tests', function () {
19
+ // ========================================================================
20
+ // USE GENERIC TEST SUITE FOR BASIC FUNCTIONALITY
21
+ // ========================================================================
22
+
23
+ createNodeTestSuite('Email Sender', emailSenderNode, EmailSenderTestConfigs);
24
+
25
+ // ========================================================================
26
+ // SPECIFIC EMAIL SENDER TESTS
27
+ // ========================================================================
28
+
29
+ describe('Email Sender Specific Tests', function () {
30
+ describe('Configuration Validation', function () {
31
+ const configTests = new TestScenarioBuilder()
32
+ .addValidScenario('valid configuration', EmailSenderTestConfigs.valid)
33
+ .addValidScenario('minimal configuration', EmailSenderTestConfigs.minimal)
34
+ .addErrorScenario(
35
+ 'missing required config',
36
+ EmailSenderTestConfigs.invalid,
37
+ "Required property 'sender' is missing",
38
+ );
39
+
40
+ configTests.getScenarios().forEach((scenario) => {
41
+ it(`should handle ${scenario.name}`, async function () {
42
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario);
43
+
44
+ // Verify node was created
45
+ expect(context.nodeInstance).to.exist;
46
+
47
+ // Check specific expectations
48
+ if (scenario.expectedError) {
49
+ NodeAssertions.expectError(context, scenario.expectedError);
50
+ } else {
51
+ NodeAssertions.expectNoErrors(context);
52
+ }
53
+
54
+ // Verify node properties
55
+ if (scenario.config.name) {
56
+ NodeAssertions.expectNodeProperty(context, 'name', scenario.config.name);
57
+ }
58
+
59
+ if (scenario.config.id) {
60
+ NodeAssertions.expectNodeProperty(context, 'id', scenario.config.id);
61
+ }
62
+ });
63
+ });
64
+ });
65
+
66
+ describe('Email Sending Functionality', function () {
67
+ const emailSendingTests = new TestScenarioBuilder()
68
+ .addStatusScenario(
69
+ 'successful email send',
70
+ EmailSenderTestConfigs.valid,
71
+ { fill: 'green', text: 'sent' },
72
+ { payload: 'test', topic: 'test message' },
73
+ withNodemailerMock({ shouldFail: false }),
74
+ )
75
+ .addStatusScenario(
76
+ 'send mail error',
77
+ { ...EmailSenderTestConfigs.valid, shouldFail: true },
78
+ { fill: 'red', text: 'error sending' },
79
+ { payload: 'test', topic: 'test message' },
80
+ withNodemailerMock({ shouldFail: true }),
81
+ )
82
+ .addStatusScenario(
83
+ 'rejected email',
84
+ { ...EmailSenderTestConfigs.valid, rejectedEmails: ['recipient@example.com'] },
85
+ { fill: 'red', text: 'rejected' },
86
+ { payload: 'test', topic: 'test message' },
87
+ withNodemailerMock({ rejectedEmails: ['recipient@example.com'] }),
88
+ )
89
+ .addStatusScenario(
90
+ 'pending email',
91
+ { ...EmailSenderTestConfigs.valid, pendingEmails: ['recipient@example.com'] },
92
+ { fill: 'yellow', text: 'pending' },
93
+ { payload: 'test', topic: 'test message' },
94
+ withNodemailerMock({ pendingEmails: ['recipient@example.com'] }),
95
+ );
96
+
97
+ emailSendingTests.getScenarios().forEach((scenario) => {
98
+ it(`should handle ${scenario.name}`, async function () {
99
+ const mockOptions: MockNodeREDOptions = scenario.mockOptions || {};
100
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario, mockOptions);
101
+
102
+ expect(context.nodeInstance).to.exist;
103
+
104
+ if (scenario.expectedStatus) {
105
+ NodeAssertions.expectStatus(context, scenario.expectedStatus);
106
+ }
107
+
108
+ if (scenario.expectedError) {
109
+ NodeAssertions.expectError(context, scenario.expectedError);
110
+ }
111
+ });
112
+ });
113
+ });
114
+
115
+ describe('Attachment Handling', function () {
116
+ const mockDependencies = {
117
+ nodemailer: createMockNodemailer({
118
+ shouldFail: false,
119
+ acceptedEmails: [],
120
+ }),
121
+ };
122
+
123
+ const mockOptions: MockNodeREDOptions = {
124
+ dependencies: mockDependencies,
125
+ statusHandler: function (status: any) {
126
+ console.log('📊 Status received:', JSON.stringify(status, null, 2));
127
+ },
128
+ errorHandler: function (err: any) {
129
+ console.log('❌ Error received:', err);
130
+ },
131
+ };
132
+
133
+ const attachmentTests = [
134
+ {
135
+ name: 'array of attachments',
136
+ config: {
137
+ ...EmailSenderTestConfigs.valid,
138
+ attachments: JSON.stringify([
139
+ { filename: 'test1.txt', content: 'First file' },
140
+ { filename: 'test2.txt', content: 'Second file' },
141
+ ]),
142
+ attachmentsType: 'json',
143
+ },
144
+ input: { payload: 'test', topic: 'test message' },
145
+ expectedStatus: { fill: 'green', text: 'sent' },
146
+ },
147
+ {
148
+ name: 'single attachment object',
149
+ config: {
150
+ ...EmailSenderTestConfigs.valid,
151
+ attachments: JSON.stringify({
152
+ filename: 'single-test.txt',
153
+ content: 'Single file content',
154
+ }),
155
+ attachmentsType: 'json',
156
+ },
157
+ input: { payload: 'test', topic: 'test message' },
158
+ expectedStatus: { fill: 'green', text: 'sent' },
159
+ },
160
+ {
161
+ name: 'empty attachments string',
162
+ config: {
163
+ ...EmailSenderTestConfigs.valid,
164
+ attachments: '',
165
+ attachmentsType: 'str',
166
+ },
167
+ input: { payload: 'test', topic: 'test message' },
168
+ expectedStatus: { fill: 'green', text: 'sent' },
169
+ },
170
+ {
171
+ name: 'malformed attachments',
172
+ config: {
173
+ ...EmailSenderTestConfigs.valid,
174
+ attachments: JSON.stringify([
175
+ { filename: 'valid.txt', content: 'Valid content' },
176
+ { filename: 'invalid.txt' }, // Missing content
177
+ ]),
178
+ attachmentsType: 'json',
179
+ },
180
+ input: { payload: 'test', topic: 'test message' },
181
+ expectedError: "Attachment object is missing 'filename' or 'content' property.",
182
+ },
183
+ ];
184
+
185
+ attachmentTests.forEach((testCase) => {
186
+ it(`should handle ${testCase.name}`, async function () {
187
+ const scenario: TestScenario = {
188
+ name: testCase.name,
189
+ config: testCase.config,
190
+ input: testCase.input,
191
+ expectedStatus: testCase.expectedStatus,
192
+ expectedError: testCase.expectedError,
193
+ timeout: 3000,
194
+ };
195
+
196
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario, mockOptions);
197
+
198
+ expect(context.nodeInstance).to.exist;
199
+
200
+ if (scenario.expectedStatus) {
201
+ NodeAssertions.expectStatus(context, scenario.expectedStatus);
202
+ }
203
+
204
+ if (scenario.expectedError) {
205
+ NodeAssertions.expectError(context, scenario.expectedError);
206
+ }
207
+ });
208
+ });
209
+ });
210
+
211
+ // ========================================================================
212
+ // DATA-DRIVEN EMAIL CONFIGURATION TESTS
213
+ // ========================================================================
214
+
215
+ describe('Email Sender Data driven tests', function () {
216
+ const mockDependencies = {
217
+ nodemailer: createMockNodemailer({
218
+ shouldFail: false,
219
+ acceptedEmails: [],
220
+ }),
221
+ };
222
+
223
+ const mockOptions: MockNodeREDOptions = {
224
+ dependencies: mockDependencies,
225
+ statusHandler: function (status: any) {
226
+ console.log('📊 Status received:', JSON.stringify(status, null, 2));
227
+ },
228
+ errorHandler: function (err: any) {
229
+ console.log('❌ Error received:', err);
230
+ },
231
+ };
232
+
233
+ const DataDrivenTests = [
234
+ {
235
+ name: 'basic text email',
236
+ input: {
237
+ payload: 'Hello World',
238
+ topic: 'Test Subject',
239
+ to: 'test@example.com',
240
+ },
241
+ },
242
+ {
243
+ name: 'HTML email',
244
+ input: {
245
+ payload: '<h1>Hello World</h1>',
246
+ topic: 'HTML Test',
247
+ to: 'test@example.com',
248
+ html: true,
249
+ },
250
+ },
251
+ {
252
+ name: 'email with custom headers',
253
+ input: {
254
+ payload: 'Custom headers test',
255
+ topic: 'Custom Headers',
256
+ to: 'test@example.com',
257
+ headers: { 'X-Custom': 'test-header' },
258
+ },
259
+ },
260
+ {
261
+ name: 'empty payload',
262
+ input: {
263
+ payload: '',
264
+ topic: 'Empty Content',
265
+ to: 'test@example.com',
266
+ },
267
+ },
268
+ {
269
+ name: 'missing recipient',
270
+ input: {
271
+ payload: 'No recipient test',
272
+ topic: 'No Recipient',
273
+ },
274
+ expectedError: /recipient|to|email/i,
275
+ },
276
+ ];
277
+
278
+ DataDrivenTests.forEach((testCase) => {
279
+ it(`should handle ${testCase.name}`, async function () {
280
+ const scenario: TestScenario = {
281
+ name: testCase.name,
282
+ config: EmailSenderTestConfigs.minimalDataDriven,
283
+ input: testCase.input,
284
+ expectedError: testCase.expectedError,
285
+ timeout: 10000,
286
+ };
287
+
288
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario, mockOptions);
289
+
290
+ expect(context.nodeInstance).to.exist;
291
+
292
+ if (scenario.expectedStatus) {
293
+ NodeAssertions.expectStatus(context, scenario.expectedStatus);
294
+ }
295
+
296
+ if (scenario.expectedError) {
297
+ NodeAssertions.expectError(context, scenario.expectedError);
298
+ }
299
+ });
300
+ });
301
+ });
302
+
303
+ // ========================================================================
304
+ // ERROR RESILIENCE TESTS
305
+ // ========================================================================
306
+
307
+ describe('Error Resilience', function () {
308
+ const resilience = new ErrorResilienceTestBuilder()
309
+ .addMalformedInputScenario('email input', EmailSenderTestConfigs.valid)
310
+ .addRapidFireScenario('rapid email sending', EmailSenderTestConfigs.valid, 10);
311
+
312
+ const mockDependencies = {
313
+ nodemailer: createMockNodemailer({
314
+ shouldFail: false,
315
+ acceptedEmails: [],
316
+ }),
317
+ };
318
+
319
+ const mockOptions: MockNodeREDOptions = {
320
+ dependencies: mockDependencies,
321
+ statusHandler: function (status: any) {
322
+ console.log('📊 Status received:', JSON.stringify(status, null, 2));
323
+ },
324
+ errorHandler: function (err: any) {
325
+ console.log('❌ Error received:', err);
326
+ },
327
+ };
328
+
329
+ // Add email-specific error scenarios
330
+ const emailErrors = new TestScenarioBuilder()
331
+ .addErrorScenario(
332
+ 'invalid SMTP config',
333
+ {
334
+ ...EmailSenderTestConfigs.valid,
335
+ hostnameost: 'invalid.smtp.server',
336
+ port: 99999,
337
+ },
338
+ /connection|smtp|invalid/i,
339
+ { payload: 'test', topic: 'test' },
340
+ withNodemailerMock({
341
+ shouldFail: true,
342
+ failureMessage: 'Connection failed: SMTP server not reachable',
343
+ failureCode: 'ECONNREFUSED',
344
+ }),
345
+ )
346
+ .addErrorScenario(
347
+ 'authentication failure',
348
+ {
349
+ ...EmailSenderTestConfigs.valid,
350
+ user: 'invalid@user.com',
351
+ password: 'wrongpassword',
352
+ },
353
+ /auth|login|credential/i,
354
+ { payload: 'test', topic: 'test' },
355
+ withNodemailerMock({
356
+ shouldFail: true,
357
+ failureMessage: 'Invalid login: 535 Authentication credentials invalid',
358
+ failureCode: 'EAUTH',
359
+ onSendMail: (mailOptions) => {
360
+ console.log('🔍 Mock sendMail called with shouldFail=true');
361
+ },
362
+ }),
363
+ );
364
+
365
+ [...resilience.getScenarios(), ...emailErrors.getScenarios()].forEach((scenario) => {
366
+ it(`should handle ${scenario.name}`, async function () {
367
+ const testMockOptions = scenario.mockOptions || mockOptions;
368
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario, testMockOptions);
369
+
370
+ expect(context.nodeInstance).to.exist;
371
+
372
+ if (scenario.expectedError) {
373
+ NodeAssertions.expectError(context, scenario.expectedError);
374
+ } else {
375
+ // Should handle gracefully without crashing
376
+ const handledGracefully =
377
+ context.errors.length === 0 || context.statuses.some((s) => s.fill === 'red');
378
+ expect(handledGracefully).to.be.true;
379
+ }
380
+ });
381
+ });
382
+ });
383
+
384
+ // ========================================================================
385
+ // EDGE CASES FOR EMAIL SENDING
386
+ // ========================================================================
387
+
388
+ describe('Email Edge Cases', function () {
389
+ const edgeCases = new EdgeCaseTestBuilder()
390
+ .addEmptyDataScenarios('empty email data', EmailSenderTestConfigs.valid)
391
+ .addSpecialCharacterScenarios('special characters in emails', EmailSenderTestConfigs.valid);
392
+
393
+ // Email-specific edge cases
394
+ const emailEdgeCases = new TestScenarioBuilder()
395
+ .addCustomScenario({
396
+ name: 'very long subject line',
397
+ config: EmailSenderTestConfigs.valid,
398
+ input: {
399
+ payload: 'test',
400
+ topic: 'a'.repeat(1000), // Very long subject
401
+ },
402
+ })
403
+ .addCustomScenario({
404
+ name: 'Unicode characters in email',
405
+ config: EmailSenderTestConfigs.valid,
406
+ input: {
407
+ payload: 'Héllo Wörld! 🌟',
408
+ topic: 'Tëst Émails 📧',
409
+ to: 'tëst@exämple.com',
410
+ },
411
+ })
412
+ .addCustomScenario({
413
+ name: 'very large email content',
414
+ config: EmailSenderTestConfigs.valid,
415
+ input: {
416
+ payload: 'x'.repeat(100000), // 100KB content
417
+ topic: 'Large Email Test',
418
+ },
419
+ });
420
+
421
+ [...edgeCases.getScenarios(), ...emailEdgeCases.getScenarios()].forEach((scenario) => {
422
+ it(`should handle ${scenario.name}`, async function () {
423
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario);
424
+ expect(context.nodeInstance).to.exist;
425
+
426
+ // Should either succeed or fail gracefully
427
+ const handledWell =
428
+ context.errors.length === 0 || context.statuses.some((s) => ['red', 'yellow'].includes(s.fill));
429
+ expect(handledWell).to.be.true;
430
+ });
431
+ });
432
+ });
433
+
434
+ // ========================================================================
435
+ // COMPREHENSIVE EMAIL SCENARIOS
436
+ // ========================================================================
437
+
438
+ describe('Complex Email Scenarios', function () {
439
+ const mockDependencies = {
440
+ nodemailer: createMockNodemailer({
441
+ shouldFail: false,
442
+ acceptedEmails: [],
443
+ }),
444
+ };
445
+
446
+ const mockOptions: MockNodeREDOptions = {
447
+ dependencies: mockDependencies,
448
+ statusHandler: function (status: any) {
449
+ console.log('📊 Status received:', JSON.stringify(status, null, 2));
450
+ },
451
+ errorHandler: function (err: any) {
452
+ console.log('❌ Error received:', err);
453
+ },
454
+ };
455
+
456
+ const complexScenarios = [
457
+ {
458
+ name: 'email with multiple recipients',
459
+ config: EmailSenderTestConfigs.valid,
460
+ input: {
461
+ payload: 'Multi-recipient test',
462
+ topic: 'Multiple Recipients',
463
+ to: 'user1@example.com,user2@example.com,user3@example.com',
464
+ },
465
+ expectedStatus: { fill: 'green', text: 'sent' },
466
+ },
467
+ {
468
+ name: 'email with CC and BCC',
469
+ config: EmailSenderTestConfigs.valid,
470
+ input: {
471
+ payload: 'CC/BCC test',
472
+ topic: 'Carbon Copy Test',
473
+ to: 'primary@example.com',
474
+ cc: 'cc@example.com',
475
+ bcc: 'bcc@example.com',
476
+ },
477
+ expectedStatus: { fill: 'green', text: 'sent' },
478
+ },
479
+ {
480
+ name: 'email with mixed attachment types',
481
+ config: {
482
+ ...EmailSenderTestConfigs.valid,
483
+ attachments: JSON.stringify([
484
+ { filename: 'text.txt', content: 'Text file' },
485
+ { filename: 'data.json', content: '{"test": true}' },
486
+ { filename: 'image.jpg', content: 'base64encodeddata...' },
487
+ ]),
488
+ attachmentsType: 'json',
489
+ },
490
+ input: {
491
+ payload: 'Mixed attachments test',
492
+ topic: 'Multiple Attachment Types',
493
+ },
494
+ expectedStatus: { fill: 'green', text: 'sent' },
495
+ },
496
+ {
497
+ name: 'email with custom priority',
498
+ config: EmailSenderTestConfigs.valid,
499
+ input: {
500
+ payload: 'High priority email',
501
+ topic: 'URGENT: Priority Test',
502
+ priority: 'high',
503
+ },
504
+ expectedStatus: { fill: 'green', text: 'sent' },
505
+ },
506
+ ];
507
+
508
+ complexScenarios.forEach((scenario) => {
509
+ it(`should handle ${scenario.name}`, async function () {
510
+ const testScenario: TestScenario = {
511
+ name: scenario.name,
512
+ config: scenario.config,
513
+ input: scenario.input,
514
+ timeout: 5000,
515
+ expectedStatus: scenario.expectedStatus,
516
+ };
517
+
518
+ const context = await NodeTestRunner.runScenario(emailSenderNode, testScenario, mockOptions);
519
+
520
+ expect(context.nodeInstance).to.exist;
521
+
522
+ // Should either send successfully or handle errors gracefully
523
+ const hasStatus = context.statuses.length > 0;
524
+ expect(hasStatus, 'Should update status for complex scenarios').to.be.true;
525
+ });
526
+ });
527
+ });
528
+
529
+ // ========================================================================
530
+ // LEGACY COMPATIBILITY
531
+ // ========================================================================
532
+
533
+ describe('Legacy Compatibility', function () {
534
+ it('should maintain module export signature', function () {
535
+ expect(emailSenderNode).to.be.a('function');
536
+ expect(emailSenderNode.length).to.equal(1); // Should accept RED parameter
537
+ });
538
+
539
+ it('should register with correct node type', async function () {
540
+ const scenario: TestScenario = {
541
+ name: 'node type registration',
542
+ config: EmailSenderTestConfigs.minimal,
543
+ };
544
+
545
+ const context = await NodeTestRunner.runScenario(emailSenderNode, scenario);
546
+ expect(context.mockRED.nodes.lastRegisteredType).to.equal('email-sender');
547
+ });
548
+ });
549
+ });
550
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist",
5
+ //set to commonjs and node for node-red compatibility
6
+ "module": "commonjs",
7
+ "moduleResolution": "node",
8
+ // set to es2021 for node-red compatibility
9
+ "target": "es2018",
10
+ "lib": ["es2018"],
11
+ "declaration": true,
12
+ "skipLibCheck": true,
13
+ "declarationDir": "dist",
14
+ "sourceMap": true,
15
+ "esModuleInterop": true,
16
+ "strict": true,
17
+ "forceConsistentCasingInFileNames": true,
18
+ "types": ["mocha", "chai", "node"],
19
+ "allowSyntheticDefaultImports": true
20
+ },
21
+ "include": ["src/test/**/*", "src/**/*"],
22
+ "exclude": ["node_modules", "dist"]
23
+ }