@postalsys/email-text-tools 2.1.16 → 2.3.3
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/.github/workflows/release.yaml +17 -17
- package/.ncurc.js +1 -2
- package/.prettierignore +14 -0
- package/.release-please-manifest.json +3 -0
- package/CHANGELOG.md +81 -31
- package/benchmark/benchmark.js +358 -0
- package/benchmark/concurrency-benchmark.js +176 -0
- package/benchmark/quick-benchmark.js +200 -0
- package/benchmark/quick-concurrency.js +64 -0
- package/benchmark/real-world-benchmark.js +267 -0
- package/docs/PERFORMANCE.md +262 -0
- package/eslint.config.js +52 -0
- package/examples/failing.html +617 -0
- package/examples/mime-html.js +262 -31
- package/lib/juice-worker.js +13 -0
- package/lib/mime-html.js +243 -13
- package/lib/text-to-html.js +1 -1
- package/lib/worker-pool.js +270 -0
- package/package.json +16 -8
- package/release-please-config.json +9 -0
- package/test/comprehensive.test.js +347 -0
- package/test/edge-cases.test.js +62 -0
- package/test/mime-html.test.js +327 -0
- package/test/worker-pool-regression.test.js +128 -0
- package/test/worker-pool.test.js +282 -0
- package/processed.txt +0 -699
|
@@ -6,32 +6,32 @@ on:
|
|
|
6
6
|
permissions:
|
|
7
7
|
contents: write
|
|
8
8
|
pull-requests: write
|
|
9
|
+
issues: write
|
|
9
10
|
id-token: write
|
|
10
11
|
|
|
11
12
|
name: release
|
|
12
13
|
jobs:
|
|
13
14
|
release-please:
|
|
14
15
|
runs-on: ubuntu-latest
|
|
16
|
+
outputs:
|
|
17
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
15
18
|
steps:
|
|
16
|
-
- uses:
|
|
19
|
+
- uses: googleapis/release-please-action@v4
|
|
17
20
|
id: release
|
|
21
|
+
|
|
22
|
+
publish:
|
|
23
|
+
needs: release-please
|
|
24
|
+
if: ${{ needs.release-please.outputs.release_created }}
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
environment: npm-publish
|
|
27
|
+
permissions:
|
|
28
|
+
contents: read
|
|
29
|
+
id-token: write
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
- uses: actions/setup-node@v4
|
|
18
33
|
with:
|
|
19
|
-
|
|
20
|
-
package-name: ${{vars.NPM_MODULE_NAME}}
|
|
21
|
-
pull-request-title-pattern: 'chore${scope}: release ${version} [skip-ci]'
|
|
22
|
-
# The logic below handles the npm publication:
|
|
23
|
-
- uses: actions/checkout@v3
|
|
24
|
-
# these if statements ensure that a publication only occurs when
|
|
25
|
-
# a new release is created:
|
|
26
|
-
if: ${{ steps.release.outputs.release_created }}
|
|
27
|
-
- uses: actions/setup-node@v3
|
|
28
|
-
with:
|
|
29
|
-
node-version: 20
|
|
34
|
+
node-version: 24
|
|
30
35
|
registry-url: 'https://registry.npmjs.org'
|
|
31
|
-
if: ${{ steps.release.outputs.release_created }}
|
|
32
36
|
- run: npm ci
|
|
33
|
-
if: ${{ steps.release.outputs.release_created }}
|
|
34
37
|
- run: npm publish --provenance --access public
|
|
35
|
-
env:
|
|
36
|
-
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
|
37
|
-
if: ${{ steps.release.outputs.release_created }}
|
package/.ncurc.js
CHANGED
package/.prettierignore
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,108 +1,158 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [2.
|
|
3
|
+
## [2.3.3](https://github.com/postalsys/email-text-tools/compare/email-text-tools-v2.3.2...email-text-tools-v2.3.3) (2025-10-23)
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
### Bug Fixes
|
|
7
7
|
|
|
8
|
-
*
|
|
8
|
+
* remove registry-url to enable OIDC authentication for trusted publishing ([319e61e](https://github.com/postalsys/email-text-tools/commit/319e61ed7c83af3db4f0a58f4b5b85c296f6f6a6))
|
|
9
|
+
* upgrade Node.js to version 24 for OIDC trusted publishing support ([fd41ca2](https://github.com/postalsys/email-text-tools/commit/fd41ca22a959c06eb2df4e8b957a0da86f42d9da))
|
|
9
10
|
|
|
10
|
-
## [2.
|
|
11
|
+
## [2.3.2](https://github.com/postalsys/email-text-tools/compare/email-text-tools-v2.3.1...email-text-tools-v2.3.2) (2025-10-23)
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
### Bug Fixes
|
|
14
15
|
|
|
15
|
-
*
|
|
16
|
+
* separate publish job with npm-publish environment for trusted publishing ([1ea55bd](https://github.com/postalsys/email-text-tools/commit/1ea55bdcfa0726f48d927fb970cf900a4cd4943f))
|
|
16
17
|
|
|
17
|
-
## [2.1
|
|
18
|
+
## [2.3.1](https://github.com/postalsys/email-text-tools/compare/email-text-tools-v2.3.0...email-text-tools-v2.3.1) (2025-10-23)
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
### Bug Fixes
|
|
21
22
|
|
|
22
|
-
*
|
|
23
|
+
* trigger release to test npm publishing configuration ([88e7110](https://github.com/postalsys/email-text-tools/commit/88e711007a73a88e0f40b5bfb278826821c1fc6a))
|
|
23
24
|
|
|
24
|
-
## [2.
|
|
25
|
+
## [2.3.0](https://github.com/postalsys/email-text-tools/compare/email-text-tools-v2.2.0...email-text-tools-v2.3.0) (2025-10-23)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* **mime-html:** add timeout protection for CSS processing with juice ([9bd3542](https://github.com/postalsys/email-text-tools/commit/9bd35426642c00c20fa1a8ce9c898f7ab7fc7e43))
|
|
25
31
|
|
|
26
32
|
|
|
27
33
|
### Bug Fixes
|
|
28
34
|
|
|
35
|
+
* bumped deps ([45f4533](https://github.com/postalsys/email-text-tools/commit/45f453390e00a8b5dea00c0ab3a7b4a742e9b3ce))
|
|
36
|
+
* Bumped deps ([519eb91](https://github.com/postalsys/email-text-tools/commit/519eb913a2aa91afe2eb1c782186f4f043ce1c55))
|
|
37
|
+
* Bumped deps ([00af333](https://github.com/postalsys/email-text-tools/commit/00af333ece8b1e6d14091fda1aea7662f314c721))
|
|
38
|
+
* Bumped deps ([da979c9](https://github.com/postalsys/email-text-tools/commit/da979c9feef5c8fd4e08b9967cbffcc058a70677))
|
|
39
|
+
* **deploy:** Set up automatic deployment ([21e55be](https://github.com/postalsys/email-text-tools/commit/21e55be18bb2ac1b991ee6000928c429a5b09ddd))
|
|
40
|
+
* **deploy:** Set up automatic deployment ([c816aaf](https://github.com/postalsys/email-text-tools/commit/c816aafa0457318cfd84497dfcd4e5628503c5b4))
|
|
29
41
|
* **deps:** Bumped deps ([3b71891](https://github.com/postalsys/email-text-tools/commit/3b71891b2c6bcb5d87fb9f583a2aec221bcb142f))
|
|
42
|
+
* **deps:** Bumped deps ([498e56a](https://github.com/postalsys/email-text-tools/commit/498e56a011321f2f437c461008724ca07233eb41))
|
|
43
|
+
* **deps:** Bumped deps ([59e44d8](https://github.com/postalsys/email-text-tools/commit/59e44d8cb0877e407becac7ef6744a4dfcdba083))
|
|
44
|
+
* **deps:** Bumped deps ([4f8a120](https://github.com/postalsys/email-text-tools/commit/4f8a1208b2841d343baf610c1391788b60b4297c))
|
|
45
|
+
* **deps:** Bumped deps ([a6711a1](https://github.com/postalsys/email-text-tools/commit/a6711a1938d8e2e75f5afd83b5a8c443be0adb9c))
|
|
46
|
+
* **deps:** Bumped deps ([15233fa](https://github.com/postalsys/email-text-tools/commit/15233fa7850f3227bfbc4f06500f0f267e651913))
|
|
47
|
+
* **deps:** Bumped deps ([4815314](https://github.com/postalsys/email-text-tools/commit/4815314f9d36da2b2163d6990acc8f68fc1bc356))
|
|
48
|
+
* **deps:** Bumped deps (juice) ([69eaee3](https://github.com/postalsys/email-text-tools/commit/69eaee36cceadbbf5ebf23caaf24385c38859a03))
|
|
49
|
+
* **deps:** fixed deps ([ccf26e2](https://github.com/postalsys/email-text-tools/commit/ccf26e2f0f8047482b9cc7e71cd0a3e61b286ddc))
|
|
50
|
+
* **deps:** removed js-beautify ([a73ccc9](https://github.com/postalsys/email-text-tools/commit/a73ccc97a4acf9bfa7e439939c41869c2554b073))
|
|
51
|
+
* **mime-html:** ensure async version pre-filters problematic CSS selectors ([5166f71](https://github.com/postalsys/email-text-tools/commit/5166f714b8532c62aa33c76b2b4e2ac3c8642ca6))
|
|
52
|
+
* removed unneeded console log lines ([3a10214](https://github.com/postalsys/email-text-tools/commit/3a1021483029a1c99df122241c4e0f6062b91059))
|
|
53
|
+
* rename release-please config file to remove dot prefix ([0bb0343](https://github.com/postalsys/email-text-tools/commit/0bb0343f7c4d35f62b66b159604ba0f19665a177))
|
|
54
|
+
* upgrade tooling and configure release-please v4 ([4620dd7](https://github.com/postalsys/email-text-tools/commit/4620dd7d67c70486789af35abb1732ee151545c0))
|
|
55
|
+
* **worker-pool:** properly return workers to free list after task completion ([2d6cd2c](https://github.com/postalsys/email-text-tools/commit/2d6cd2c451941932d44d2ce025a5ba867ec66fec))
|
|
30
56
|
|
|
31
|
-
## [2.
|
|
57
|
+
## [2.2.0](https://github.com/postalsys/email-text-tools/compare/v2.1.16...v2.2.0) (2025-09-29)
|
|
32
58
|
|
|
59
|
+
### Features
|
|
60
|
+
|
|
61
|
+
- **mime-html:** add timeout protection for CSS processing with juice ([9bd3542](https://github.com/postalsys/email-text-tools/commit/9bd35426642c00c20fa1a8ce9c898f7ab7fc7e43))
|
|
33
62
|
|
|
34
63
|
### Bug Fixes
|
|
35
64
|
|
|
36
|
-
|
|
65
|
+
- **mime-html:** ensure async version pre-filters problematic CSS selectors ([5166f71](https://github.com/postalsys/email-text-tools/commit/5166f714b8532c62aa33c76b2b4e2ac3c8642ca6))
|
|
66
|
+
- **worker-pool:** properly return workers to free list after task completion ([2d6cd2c](https://github.com/postalsys/email-text-tools/commit/2d6cd2c451941932d44d2ce025a5ba867ec66fec))
|
|
37
67
|
|
|
38
|
-
## [2.1.
|
|
68
|
+
## [2.1.16](https://github.com/postalsys/email-text-tools/compare/v2.1.15...v2.1.16) (2025-06-29)
|
|
39
69
|
|
|
70
|
+
### Bug Fixes
|
|
71
|
+
|
|
72
|
+
- removed unneeded console log lines ([3a10214](https://github.com/postalsys/email-text-tools/commit/3a1021483029a1c99df122241c4e0f6062b91059))
|
|
73
|
+
|
|
74
|
+
## [2.1.15](https://github.com/postalsys/email-text-tools/compare/v2.1.14...v2.1.15) (2025-05-20)
|
|
40
75
|
|
|
41
76
|
### Bug Fixes
|
|
42
77
|
|
|
43
|
-
|
|
78
|
+
- Bumped deps ([519eb91](https://github.com/postalsys/email-text-tools/commit/519eb913a2aa91afe2eb1c782186f4f043ce1c55))
|
|
44
79
|
|
|
45
|
-
## [2.1.
|
|
80
|
+
## [2.1.14](https://github.com/postalsys/email-text-tools/compare/v2.1.13...v2.1.14) (2025-02-22)
|
|
46
81
|
|
|
82
|
+
### Bug Fixes
|
|
83
|
+
|
|
84
|
+
- Bumped deps ([00af333](https://github.com/postalsys/email-text-tools/commit/00af333ece8b1e6d14091fda1aea7662f314c721))
|
|
85
|
+
|
|
86
|
+
## [2.1.13](https://github.com/postalsys/email-text-tools/compare/v2.1.12...v2.1.13) (2025-01-26)
|
|
47
87
|
|
|
48
88
|
### Bug Fixes
|
|
49
89
|
|
|
50
|
-
|
|
90
|
+
- **deps:** Bumped deps ([3b71891](https://github.com/postalsys/email-text-tools/commit/3b71891b2c6bcb5d87fb9f583a2aec221bcb142f))
|
|
51
91
|
|
|
52
|
-
## [2.1.
|
|
92
|
+
## [2.1.12](https://github.com/postalsys/email-text-tools/compare/v2.1.11...v2.1.12) (2024-12-03)
|
|
53
93
|
|
|
94
|
+
### Bug Fixes
|
|
95
|
+
|
|
96
|
+
- **deps:** Bumped deps ([498e56a](https://github.com/postalsys/email-text-tools/commit/498e56a011321f2f437c461008724ca07233eb41))
|
|
97
|
+
|
|
98
|
+
## [2.1.11](https://github.com/postalsys/email-text-tools/compare/v2.1.10...v2.1.11) (2024-09-08)
|
|
54
99
|
|
|
55
100
|
### Bug Fixes
|
|
56
101
|
|
|
57
|
-
|
|
102
|
+
- Bumped deps ([da979c9](https://github.com/postalsys/email-text-tools/commit/da979c9feef5c8fd4e08b9967cbffcc058a70677))
|
|
58
103
|
|
|
59
|
-
## [2.1.
|
|
104
|
+
## [2.1.10](https://github.com/postalsys/email-text-tools/compare/v2.1.9...v2.1.10) (2024-08-22)
|
|
60
105
|
|
|
106
|
+
### Bug Fixes
|
|
107
|
+
|
|
108
|
+
- **deps:** Bumped deps (juice) ([69eaee3](https://github.com/postalsys/email-text-tools/commit/69eaee36cceadbbf5ebf23caaf24385c38859a03))
|
|
109
|
+
|
|
110
|
+
## [2.1.9](https://github.com/postalsys/email-text-tools/compare/v2.1.8...v2.1.9) (2024-07-03)
|
|
61
111
|
|
|
62
112
|
### Bug Fixes
|
|
63
113
|
|
|
64
|
-
|
|
114
|
+
- bumped deps ([45f4533](https://github.com/postalsys/email-text-tools/commit/45f453390e00a8b5dea00c0ab3a7b4a742e9b3ce))
|
|
65
115
|
|
|
66
|
-
## [2.1.
|
|
116
|
+
## [2.1.8](https://github.com/postalsys/email-text-tools/compare/v2.1.7...v2.1.8) (2024-04-12)
|
|
117
|
+
|
|
118
|
+
### Bug Fixes
|
|
119
|
+
|
|
120
|
+
- **deps:** Bumped deps ([59e44d8](https://github.com/postalsys/email-text-tools/commit/59e44d8cb0877e407becac7ef6744a4dfcdba083))
|
|
67
121
|
|
|
122
|
+
## [2.1.7](https://github.com/postalsys/email-text-tools/compare/v2.1.6...v2.1.7) (2024-02-29)
|
|
68
123
|
|
|
69
124
|
### Bug Fixes
|
|
70
125
|
|
|
71
|
-
|
|
126
|
+
- **deps:** Bumped deps ([4f8a120](https://github.com/postalsys/email-text-tools/commit/4f8a1208b2841d343baf610c1391788b60b4297c))
|
|
72
127
|
|
|
73
128
|
## [2.1.6](https://github.com/postalsys/email-text-tools/compare/v2.1.5...v2.1.6) (2024-02-18)
|
|
74
129
|
|
|
75
|
-
|
|
76
130
|
### Bug Fixes
|
|
77
131
|
|
|
78
|
-
|
|
132
|
+
- **deps:** removed js-beautify ([a73ccc9](https://github.com/postalsys/email-text-tools/commit/a73ccc97a4acf9bfa7e439939c41869c2554b073))
|
|
79
133
|
|
|
80
134
|
## [2.1.5](https://github.com/postalsys/email-text-tools/compare/v2.1.4...v2.1.5) (2024-02-18)
|
|
81
135
|
|
|
82
|
-
|
|
83
136
|
### Bug Fixes
|
|
84
137
|
|
|
85
|
-
|
|
138
|
+
- **deps:** fixed deps ([ccf26e2](https://github.com/postalsys/email-text-tools/commit/ccf26e2f0f8047482b9cc7e71cd0a3e61b286ddc))
|
|
86
139
|
|
|
87
140
|
## [2.1.4](https://github.com/postalsys/email-text-tools/compare/v2.1.3...v2.1.4) (2024-02-18)
|
|
88
141
|
|
|
89
|
-
|
|
90
142
|
### Bug Fixes
|
|
91
143
|
|
|
92
|
-
|
|
93
|
-
|
|
144
|
+
- **deps:** Bumped deps ([a6711a1](https://github.com/postalsys/email-text-tools/commit/a6711a1938d8e2e75f5afd83b5a8c443be0adb9c))
|
|
145
|
+
- **deps:** Bumped deps ([15233fa](https://github.com/postalsys/email-text-tools/commit/15233fa7850f3227bfbc4f06500f0f267e651913))
|
|
94
146
|
|
|
95
147
|
## [2.1.3](https://github.com/postalsys/email-text-tools/compare/v2.1.2...v2.1.3) (2023-10-31)
|
|
96
148
|
|
|
97
|
-
|
|
98
149
|
### Bug Fixes
|
|
99
150
|
|
|
100
|
-
|
|
151
|
+
- **deps:** Bumped deps ([4815314](https://github.com/postalsys/email-text-tools/commit/4815314f9d36da2b2163d6990acc8f68fc1bc356))
|
|
101
152
|
|
|
102
153
|
## [2.1.2](https://github.com/postalsys/email-text-tools/compare/v2.1.1...v2.1.2) (2023-10-20)
|
|
103
154
|
|
|
104
|
-
|
|
105
155
|
### Bug Fixes
|
|
106
156
|
|
|
107
|
-
|
|
108
|
-
|
|
157
|
+
- **deploy:** Set up automatic deployment ([21e55be](https://github.com/postalsys/email-text-tools/commit/21e55be18bb2ac1b991ee6000928c429a5b09ddd))
|
|
158
|
+
- **deploy:** Set up automatic deployment ([c816aaf](https://github.com/postalsys/email-text-tools/commit/c816aafa0457318cfd84497dfcd4e5628503c5b4))
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const mimeHtml = require('../lib/mime-html');
|
|
7
|
+
|
|
8
|
+
// Test data sets
|
|
9
|
+
const testCases = {
|
|
10
|
+
simple: {
|
|
11
|
+
name: 'Simple HTML',
|
|
12
|
+
html: `
|
|
13
|
+
<!DOCTYPE html>
|
|
14
|
+
<html>
|
|
15
|
+
<head>
|
|
16
|
+
<style>
|
|
17
|
+
body { font-family: Arial; }
|
|
18
|
+
p { color: blue; }
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<h1>Hello World</h1>
|
|
23
|
+
<p>This is a simple test email.</p>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
26
|
+
`
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
moderate: {
|
|
30
|
+
name: 'Moderate HTML with inline styles',
|
|
31
|
+
html: `
|
|
32
|
+
<!DOCTYPE html>
|
|
33
|
+
<html>
|
|
34
|
+
<head>
|
|
35
|
+
<style>
|
|
36
|
+
body { font-family: Arial, sans-serif; background: #f0f0f0; }
|
|
37
|
+
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
|
|
38
|
+
h1 { color: #333; border-bottom: 2px solid #007bff; }
|
|
39
|
+
p { line-height: 1.6; color: #666; }
|
|
40
|
+
.button { display: inline-block; padding: 10px 20px; background: #007bff; color: white; text-decoration: none; }
|
|
41
|
+
.footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; }
|
|
42
|
+
</style>
|
|
43
|
+
</head>
|
|
44
|
+
<body>
|
|
45
|
+
<div class="container">
|
|
46
|
+
<h1>Newsletter Title</h1>
|
|
47
|
+
<p>This is a moderately complex email template with various styles.</p>
|
|
48
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
|
49
|
+
<a href="#" class="button">Call to Action</a>
|
|
50
|
+
<div class="footer">
|
|
51
|
+
<p>Footer content here</p>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</body>
|
|
55
|
+
</html>
|
|
56
|
+
`
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
complex: {
|
|
60
|
+
name: 'Complex HTML with media queries',
|
|
61
|
+
html: `
|
|
62
|
+
<!DOCTYPE html>
|
|
63
|
+
<html>
|
|
64
|
+
<head>
|
|
65
|
+
<style>
|
|
66
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
67
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; }
|
|
68
|
+
.wrapper { max-width: 600px; margin: 0 auto; }
|
|
69
|
+
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px 20px; }
|
|
70
|
+
.header h1 { color: white; font-size: 32px; }
|
|
71
|
+
.content { padding: 40px 20px; background: white; }
|
|
72
|
+
.card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; margin-bottom: 20px; }
|
|
73
|
+
.card h2 { color: #333; margin-bottom: 10px; }
|
|
74
|
+
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
|
|
75
|
+
@media only screen and (max-width: 600px) {
|
|
76
|
+
.grid { grid-template-columns: 1fr; }
|
|
77
|
+
.header h1 { font-size: 24px; }
|
|
78
|
+
}
|
|
79
|
+
table { width: 100%; border-collapse: collapse; }
|
|
80
|
+
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
|
|
81
|
+
.button { display: inline-block; padding: 12px 24px; background: #007bff; color: white; text-decoration: none; border-radius: 4px; }
|
|
82
|
+
.footer { background: #f8f9fa; padding: 30px 20px; text-align: center; color: #6c757d; }
|
|
83
|
+
</style>
|
|
84
|
+
</head>
|
|
85
|
+
<body>
|
|
86
|
+
<div class="wrapper">
|
|
87
|
+
<div class="header">
|
|
88
|
+
<h1>Complex Email Template</h1>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="content">
|
|
91
|
+
<div class="card">
|
|
92
|
+
<h2>Feature One</h2>
|
|
93
|
+
<p>Description of the first feature with detailed information.</p>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="grid">
|
|
96
|
+
<div class="card">
|
|
97
|
+
<h2>Item 1</h2>
|
|
98
|
+
<p>Grid item content</p>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="card">
|
|
101
|
+
<h2>Item 2</h2>
|
|
102
|
+
<p>Grid item content</p>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<table>
|
|
106
|
+
<tr><th>Product</th><th>Price</th><th>Quantity</th></tr>
|
|
107
|
+
<tr><td>Item A</td><td>$10</td><td>2</td></tr>
|
|
108
|
+
<tr><td>Item B</td><td>$20</td><td>1</td></tr>
|
|
109
|
+
</table>
|
|
110
|
+
<a href="#" class="button">Shop Now</a>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="footer">
|
|
113
|
+
<p>Copyright 2024. All rights reserved.</p>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</body>
|
|
117
|
+
</html>
|
|
118
|
+
`
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
problematic: {
|
|
122
|
+
name: 'HTML with problematic CSS (modern selectors)',
|
|
123
|
+
html: `
|
|
124
|
+
<!DOCTYPE html>
|
|
125
|
+
<html>
|
|
126
|
+
<head>
|
|
127
|
+
<style>
|
|
128
|
+
body { font-family: system-ui, sans-serif; }
|
|
129
|
+
/* Modern CSS that might cause issues */
|
|
130
|
+
.container:is(.active, .highlighted) { background: yellow; }
|
|
131
|
+
.item:where(.primary) { color: blue; }
|
|
132
|
+
.parent:has(> .child) { border: 1px solid red; }
|
|
133
|
+
/* Standard CSS */
|
|
134
|
+
h1 { color: #333; }
|
|
135
|
+
p { line-height: 1.6; }
|
|
136
|
+
.box:not(.special) { padding: 10px; }
|
|
137
|
+
</style>
|
|
138
|
+
</head>
|
|
139
|
+
<body>
|
|
140
|
+
<div class="container active">
|
|
141
|
+
<h1>Test with Modern CSS</h1>
|
|
142
|
+
<div class="parent">
|
|
143
|
+
<div class="child">Child element</div>
|
|
144
|
+
</div>
|
|
145
|
+
<p class="item primary">This uses modern selectors</p>
|
|
146
|
+
<div class="box">Regular box</div>
|
|
147
|
+
<div class="box special">Special box</div>
|
|
148
|
+
</div>
|
|
149
|
+
</body>
|
|
150
|
+
</html>
|
|
151
|
+
`
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Load the failing.html if it exists
|
|
156
|
+
try {
|
|
157
|
+
const failingHtml = fs.readFileSync(path.join(__dirname, '../examples/failing.html'), 'utf8');
|
|
158
|
+
testCases.realWorld = {
|
|
159
|
+
name: 'Real-world problematic HTML',
|
|
160
|
+
html: failingHtml
|
|
161
|
+
};
|
|
162
|
+
} catch (_err) {
|
|
163
|
+
// File doesn't exist, skip it
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Benchmark runner
|
|
167
|
+
class Benchmark {
|
|
168
|
+
constructor() {
|
|
169
|
+
this.results = [];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async runTest(name, fn, iterations = 100) {
|
|
173
|
+
const times = [];
|
|
174
|
+
const errors = [];
|
|
175
|
+
|
|
176
|
+
// Warmup
|
|
177
|
+
for (let i = 0; i < 5; i++) {
|
|
178
|
+
try {
|
|
179
|
+
await fn();
|
|
180
|
+
} catch (_err) {
|
|
181
|
+
// Ignore warmup errors
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Actual test
|
|
186
|
+
for (let i = 0; i < iterations; i++) {
|
|
187
|
+
const start = process.hrtime.bigint();
|
|
188
|
+
try {
|
|
189
|
+
await fn();
|
|
190
|
+
const end = process.hrtime.bigint();
|
|
191
|
+
times.push(Number(end - start) / 1000000); // Convert to milliseconds
|
|
192
|
+
} catch (err) {
|
|
193
|
+
errors.push(err.message);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (times.length > 0) {
|
|
198
|
+
times.sort((a, b) => a - b);
|
|
199
|
+
const avg = times.reduce((a, b) => a + b, 0) / times.length;
|
|
200
|
+
const median = times[Math.floor(times.length / 2)];
|
|
201
|
+
const min = times[0];
|
|
202
|
+
const max = times[times.length - 1];
|
|
203
|
+
const p95 = times[Math.floor(times.length * 0.95)];
|
|
204
|
+
const p99 = times[Math.floor(times.length * 0.99)];
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
name,
|
|
208
|
+
iterations,
|
|
209
|
+
successful: times.length,
|
|
210
|
+
failed: errors.length,
|
|
211
|
+
avg: avg.toFixed(2),
|
|
212
|
+
median: median.toFixed(2),
|
|
213
|
+
min: min.toFixed(2),
|
|
214
|
+
max: max.toFixed(2),
|
|
215
|
+
p95: p95.toFixed(2),
|
|
216
|
+
p99: p99.toFixed(2),
|
|
217
|
+
errors: errors.length > 0 ? errors[0] : null
|
|
218
|
+
};
|
|
219
|
+
} else {
|
|
220
|
+
return {
|
|
221
|
+
name,
|
|
222
|
+
iterations,
|
|
223
|
+
successful: 0,
|
|
224
|
+
failed: errors.length,
|
|
225
|
+
errors: errors[0] || 'All iterations failed'
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
formatResults(results) {
|
|
231
|
+
console.log('\n' + '='.repeat(80));
|
|
232
|
+
console.log(`Test Case: ${results.testCase}`);
|
|
233
|
+
console.log('='.repeat(80));
|
|
234
|
+
|
|
235
|
+
const table = [];
|
|
236
|
+
results.tests.forEach(test => {
|
|
237
|
+
if (test.successful > 0) {
|
|
238
|
+
table.push({
|
|
239
|
+
Method: test.name,
|
|
240
|
+
'Success Rate': `${test.successful}/${test.iterations}`,
|
|
241
|
+
'Avg (ms)': test.avg,
|
|
242
|
+
'Median (ms)': test.median,
|
|
243
|
+
'Min (ms)': test.min,
|
|
244
|
+
'Max (ms)': test.max,
|
|
245
|
+
'P95 (ms)': test.p95,
|
|
246
|
+
'P99 (ms)': test.p99
|
|
247
|
+
});
|
|
248
|
+
} else {
|
|
249
|
+
table.push({
|
|
250
|
+
Method: test.name,
|
|
251
|
+
'Success Rate': `${test.successful}/${test.iterations}`,
|
|
252
|
+
Error: test.errors
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
console.table(table);
|
|
258
|
+
|
|
259
|
+
// Calculate speedup if both succeeded
|
|
260
|
+
const syncTest = results.tests.find(t => t.name === 'Sync');
|
|
261
|
+
const asyncTest = results.tests.find(t => t.name === 'Async (with pool)');
|
|
262
|
+
|
|
263
|
+
if (syncTest && asyncTest && syncTest.successful > 0 && asyncTest.successful > 0) {
|
|
264
|
+
const speedup = (parseFloat(syncTest.avg) / parseFloat(asyncTest.avg)).toFixed(2);
|
|
265
|
+
if (speedup > 1) {
|
|
266
|
+
console.log(`\nAsync is ${speedup}x faster than Sync`);
|
|
267
|
+
} else {
|
|
268
|
+
console.log(`\nSync is ${(1 / speedup).toFixed(2)}x faster than Async`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async runBenchmarks() {
|
|
274
|
+
console.log('Starting Mime HTML Benchmarks...');
|
|
275
|
+
console.log('================================\n');
|
|
276
|
+
|
|
277
|
+
for (const [_key, testCase] of Object.entries(testCases)) {
|
|
278
|
+
const results = {
|
|
279
|
+
testCase: testCase.name,
|
|
280
|
+
tests: []
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Test sync version
|
|
284
|
+
results.tests.push(
|
|
285
|
+
await this.runTest(
|
|
286
|
+
'Sync',
|
|
287
|
+
() => {
|
|
288
|
+
return Promise.resolve(mimeHtml.sync({ html: testCase.html }));
|
|
289
|
+
},
|
|
290
|
+
100
|
|
291
|
+
)
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
// Test async version with pool
|
|
295
|
+
results.tests.push(
|
|
296
|
+
await this.runTest(
|
|
297
|
+
'Async (with pool)',
|
|
298
|
+
async () => {
|
|
299
|
+
return await mimeHtml.async(
|
|
300
|
+
{ html: testCase.html },
|
|
301
|
+
{
|
|
302
|
+
useWorkerPool: true,
|
|
303
|
+
timeout: 5000,
|
|
304
|
+
minWorkers: 2,
|
|
305
|
+
maxWorkers: 4
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
},
|
|
309
|
+
100
|
|
310
|
+
)
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
// Test async version without pool
|
|
314
|
+
results.tests.push(
|
|
315
|
+
await this.runTest(
|
|
316
|
+
'Async (no pool)',
|
|
317
|
+
async () => {
|
|
318
|
+
return await mimeHtml.async(
|
|
319
|
+
{ html: testCase.html },
|
|
320
|
+
{
|
|
321
|
+
useWorkerPool: false,
|
|
322
|
+
timeout: 5000
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
},
|
|
326
|
+
100
|
|
327
|
+
)
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
this.formatResults(results);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Show worker pool stats
|
|
334
|
+
const stats = mimeHtml.getWorkerPoolStats();
|
|
335
|
+
if (stats) {
|
|
336
|
+
console.log('\n' + '='.repeat(80));
|
|
337
|
+
console.log('Worker Pool Stats:');
|
|
338
|
+
console.log('='.repeat(80));
|
|
339
|
+
console.table([stats]);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Clean up
|
|
343
|
+
await mimeHtml.closeWorkerPool();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Run benchmarks
|
|
348
|
+
const benchmark = new Benchmark();
|
|
349
|
+
benchmark
|
|
350
|
+
.runBenchmarks()
|
|
351
|
+
.then(() => {
|
|
352
|
+
console.log('\nBenchmark complete!');
|
|
353
|
+
process.exit(0);
|
|
354
|
+
})
|
|
355
|
+
.catch(err => {
|
|
356
|
+
console.error('Benchmark failed:', err);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
});
|