kn-es-features 1.0.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.
Files changed (48) hide show
  1. package/dist/esfeatures.iife.js +45 -0
  2. package/dist/esfeatures.js +3795 -0
  3. package/dist/esfeatures.umd.cjs +45 -0
  4. package/dist/polyfills.iife.js +7 -0
  5. package/package.json +39 -0
  6. package/src/features/es2015/01-let-const.js +54 -0
  7. package/src/features/es2015/02-arrow-functions.js +68 -0
  8. package/src/features/es2015/03-template-literals.js +51 -0
  9. package/src/features/es2015/04-destructuring.js +68 -0
  10. package/src/features/es2015/05-default-rest-spread.js +87 -0
  11. package/src/features/es2015/06-classes.js +100 -0
  12. package/src/features/es2015/07-promises.js +79 -0
  13. package/src/features/es2015/08-symbols.js +85 -0
  14. package/src/features/es2015/09-iterators-generators.js +104 -0
  15. package/src/features/es2015/10-map-set.js +106 -0
  16. package/src/features/es2015/11-proxy-reflect.js +122 -0
  17. package/src/features/es2015/12-enhanced-objects.js +101 -0
  18. package/src/features/es2015/13-new-methods.js +123 -0
  19. package/src/features/es2015/14-modules.js +38 -0
  20. package/src/features/es2015/15-binary-octal-unicode.js +65 -0
  21. package/src/features/es2015/16-for-of.js +75 -0
  22. package/src/features/es2015/17-map.js +80 -0
  23. package/src/features/es2022/01-class-fields.js +114 -0
  24. package/src/features/es2022/02-class-static-blocks.js +108 -0
  25. package/src/features/es2022/03-at-method.js +86 -0
  26. package/src/features/es2022/04-object-has-own.js +82 -0
  27. package/src/features/es2022/05-error-cause.js +92 -0
  28. package/src/features/es2022/06-regexp-d-flag.js +89 -0
  29. package/src/features/es2022/07-top-level-await.js +84 -0
  30. package/src/features/es2025/01-iterator-helpers.js +96 -0
  31. package/src/features/es2025/02-set-methods.js +92 -0
  32. package/src/features/es2025/03-promise-try.js +72 -0
  33. package/src/features/es2025/04-regexp-duplicate-groups.js +69 -0
  34. package/src/features/es2025/05-uint8array-base64-hex.js +94 -0
  35. package/src/features/es2025/06-json-parse-source.js +86 -0
  36. package/src/features/es2025/07-error-is-error.js +83 -0
  37. package/src/features/es2025/08-float16array.js +88 -0
  38. package/src/features/es2026/01-math-sum-precise.js +79 -0
  39. package/src/features/es2026/02-regexp-escape.js +80 -0
  40. package/src/features/es2026/03-explicit-resource-management.js +117 -0
  41. package/src/features/es2026/04-atomics-pause.js +81 -0
  42. package/src/features/es2026/05-import-attributes.js +86 -0
  43. package/src/index.js +166 -0
  44. package/src/main.js +226 -0
  45. package/src/polyfills.js +6 -0
  46. package/src/run.js +3 -0
  47. package/src/style.css +412 -0
  48. package/src/utils/runner.js +55 -0
package/src/style.css ADDED
@@ -0,0 +1,412 @@
1
+ /* ─── CSS Custom Properties ─────────────────────────────────────── */
2
+ :root {
3
+ --c-bg: #f2f2f7;
4
+ --c-surface: #ffffff;
5
+ --c-surface-2: #f9f9fb;
6
+ --c-pass: #30d158;
7
+ --c-pass-bg: #f0fdf4;
8
+ --c-fail: #ff453a;
9
+ --c-fail-bg: #fff5f5;
10
+ --c-accent: #007aff;
11
+ --c-accent-dark: #0055d4;
12
+ --c-text: #1c1c1e;
13
+ --c-text-2: #3c3c43;
14
+ --c-text-3: #8e8e93;
15
+ --c-border: #e5e5ea;
16
+ --c-shadow: 0 1px 3px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.04);
17
+ --radius: 12px;
18
+ --radius-sm: 8px;
19
+ --radius-xs: 5px;
20
+ --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC',
21
+ 'Helvetica Neue', sans-serif;
22
+ --mono: 'SF Mono', 'Fira Code', 'Fira Mono', Menlo, monospace;
23
+ }
24
+
25
+ /* ─── Reset ─────────────────────────────────────────────────────── */
26
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
27
+
28
+ body {
29
+ font-family: var(--font);
30
+ background: var(--c-bg);
31
+ color: var(--c-text);
32
+ font-size: 14px;
33
+ line-height: 1.5;
34
+ min-height: 100vh;
35
+ -webkit-font-smoothing: antialiased;
36
+ }
37
+
38
+ /* ─── App container ─────────────────────────────────────────────── */
39
+ .app {
40
+ max-width: 860px;
41
+ margin: 0 auto;
42
+ padding: 0 16px 64px;
43
+ }
44
+
45
+ /* ─── Header ────────────────────────────────────────────────────── */
46
+ .header {
47
+ display: flex;
48
+ align-items: center;
49
+ justify-content: space-between;
50
+ padding: 24px 0 20px;
51
+ }
52
+
53
+ .header__brand {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 12px;
57
+ }
58
+
59
+ .header__logo {
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ width: 36px;
64
+ height: 36px;
65
+ border-radius: 10px;
66
+ background: linear-gradient(135deg, #007aff 0%, #5856d6 100%);
67
+ color: #fff;
68
+ font-size: 13px;
69
+ font-weight: 800;
70
+ letter-spacing: -0.03em;
71
+ }
72
+
73
+ .header__title {
74
+ font-size: 20px;
75
+ font-weight: 600;
76
+ color: var(--c-text);
77
+ }
78
+
79
+ /* ─── Run button ────────────────────────────────────────────────── */
80
+ .btn-run {
81
+ display: flex;
82
+ align-items: center;
83
+ gap: 6px;
84
+ padding: 9px 20px;
85
+ border: none;
86
+ border-radius: 100px;
87
+ background: var(--c-accent);
88
+ color: #fff;
89
+ font-family: var(--font);
90
+ font-size: 14px;
91
+ font-weight: 500;
92
+ cursor: pointer;
93
+ transition: background .15s, transform .1s, opacity .15s;
94
+ outline: none;
95
+ }
96
+
97
+ .btn-run:hover { background: var(--c-accent-dark); }
98
+ .btn-run:active { transform: scale(.97); }
99
+
100
+ .btn-run--running,
101
+ .btn-run:disabled {
102
+ opacity: .55;
103
+ cursor: not-allowed;
104
+ }
105
+
106
+ .btn-run__icon {
107
+ font-size: 12px;
108
+ line-height: 1;
109
+ }
110
+
111
+ /* ─── Summary bar ───────────────────────────────────────────────── */
112
+ .summary {
113
+ display: flex;
114
+ align-items: center;
115
+ background: var(--c-surface);
116
+ border-radius: var(--radius);
117
+ box-shadow: var(--c-shadow);
118
+ padding: 0;
119
+ margin-bottom: 14px;
120
+ overflow: hidden;
121
+ }
122
+
123
+ .summary__group {
124
+ flex: 1;
125
+ display: flex;
126
+ flex-direction: column;
127
+ align-items: center;
128
+ gap: 2px;
129
+ padding: 14px 12px;
130
+ }
131
+
132
+ .summary__divider {
133
+ width: 1px;
134
+ height: 36px;
135
+ background: var(--c-border);
136
+ flex-shrink: 0;
137
+ }
138
+
139
+ .summary__label {
140
+ font-size: 11px;
141
+ font-weight: 500;
142
+ color: var(--c-text-3);
143
+ text-transform: uppercase;
144
+ letter-spacing: .06em;
145
+ }
146
+
147
+ .summary__value {
148
+ font-size: 20px;
149
+ font-weight: 600;
150
+ color: var(--c-text-2);
151
+ font-variant-numeric: tabular-nums;
152
+ transition: color .2s;
153
+ }
154
+
155
+ .summary__value--pass { color: var(--c-pass); }
156
+ .summary__value--fail { color: var(--c-fail); }
157
+
158
+ /* ─── Tabs ──────────────────────────────────────────────────────── */
159
+ .tabs {
160
+ display: flex;
161
+ gap: 8px;
162
+ margin-bottom: 14px;
163
+ }
164
+
165
+ .tab {
166
+ flex: 1;
167
+ display: flex;
168
+ align-items: center;
169
+ justify-content: center;
170
+ gap: 8px;
171
+ padding: 10px 16px;
172
+ border: none;
173
+ border-radius: var(--radius-sm);
174
+ background: var(--c-surface);
175
+ color: var(--c-text-3);
176
+ font-family: var(--font);
177
+ font-size: 14px;
178
+ font-weight: 500;
179
+ cursor: pointer;
180
+ box-shadow: var(--c-shadow);
181
+ transition: background .15s, color .15s, box-shadow .15s;
182
+ outline: none;
183
+ }
184
+
185
+ .tab:hover {
186
+ background: var(--c-surface-2);
187
+ color: var(--c-text);
188
+ }
189
+
190
+ .tab--active {
191
+ background: var(--c-accent);
192
+ color: #fff;
193
+ box-shadow: 0 2px 10px rgba(0,122,255,.3);
194
+ }
195
+
196
+ .tab--active:hover { background: var(--c-accent-dark); }
197
+
198
+ .tab__badge {
199
+ display: inline-flex;
200
+ align-items: center;
201
+ justify-content: center;
202
+ min-width: 22px;
203
+ padding: 1px 6px;
204
+ border-radius: 100px;
205
+ font-size: 11px;
206
+ font-weight: 600;
207
+ background: rgba(0,0,0,.1);
208
+ color: inherit;
209
+ transition: background .15s;
210
+ }
211
+
212
+ .tab--active .tab__badge { background: rgba(255,255,255,.25); }
213
+ .tab__badge--pass { background: var(--c-pass-bg); color: var(--c-pass); }
214
+ .tab__badge--fail { background: var(--c-fail-bg); color: var(--c-fail); }
215
+ .tab--active .tab__badge--pass { background: rgba(255,255,255,.25); color: #fff; }
216
+ .tab--active .tab__badge--fail { background: rgba(255,255,255,.25); color: #fff; }
217
+
218
+ /* ─── Panels ────────────────────────────────────────────────────── */
219
+ .panel { display: none; }
220
+ .panel--active { display: block; }
221
+
222
+ /* ─── Placeholder ───────────────────────────────────────────────── */
223
+ .placeholder {
224
+ display: flex;
225
+ flex-direction: column;
226
+ align-items: center;
227
+ justify-content: center;
228
+ gap: 12px;
229
+ padding: 72px 0;
230
+ }
231
+
232
+ .placeholder__icon {
233
+ font-size: 36px;
234
+ opacity: .3;
235
+ }
236
+
237
+ .placeholder__text {
238
+ font-size: 14px;
239
+ color: var(--c-text-3);
240
+ }
241
+
242
+ /* ─── Loader ────────────────────────────────────────────────────── */
243
+ .loader {
244
+ display: flex;
245
+ align-items: center;
246
+ justify-content: center;
247
+ gap: 10px;
248
+ padding: 60px 0;
249
+ color: var(--c-text-3);
250
+ font-size: 14px;
251
+ }
252
+
253
+ .loader__spinner {
254
+ width: 18px;
255
+ height: 18px;
256
+ border: 2px solid var(--c-border);
257
+ border-top-color: var(--c-accent);
258
+ border-radius: 50%;
259
+ animation: spin .7s linear infinite;
260
+ flex-shrink: 0;
261
+ }
262
+
263
+ @keyframes spin {
264
+ to { transform: rotate(360deg); }
265
+ }
266
+
267
+ /* ─── Suite card ────────────────────────────────────────────────── */
268
+ .suite {
269
+ background: var(--c-surface);
270
+ border-radius: var(--radius);
271
+ box-shadow: var(--c-shadow);
272
+ margin-bottom: 10px;
273
+ overflow: hidden;
274
+ }
275
+
276
+ .suite__header {
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: space-between;
280
+ padding: 11px 14px;
281
+ cursor: pointer;
282
+ user-select: none;
283
+ transition: background .12s;
284
+ }
285
+
286
+ .suite__header:hover { background: var(--c-surface-2); }
287
+
288
+ .suite__header-left {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: 10px;
292
+ }
293
+
294
+ .suite__indicator {
295
+ width: 3px;
296
+ height: 16px;
297
+ border-radius: 2px;
298
+ flex-shrink: 0;
299
+ }
300
+
301
+ .suite__indicator--pass { background: var(--c-pass); }
302
+ .suite__indicator--fail { background: var(--c-fail); }
303
+
304
+ .suite__name {
305
+ font-size: 14px;
306
+ font-weight: 600;
307
+ color: var(--c-text);
308
+ }
309
+
310
+ .suite__header-right {
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 10px;
314
+ }
315
+
316
+ .suite__stat {
317
+ font-size: 12px;
318
+ font-weight: 600;
319
+ padding: 2px 9px;
320
+ border-radius: 100px;
321
+ }
322
+
323
+ .suite__stat--pass { background: var(--c-pass-bg); color: var(--c-pass); }
324
+ .suite__stat--fail { background: var(--c-fail-bg); color: var(--c-fail); }
325
+
326
+ .suite__chevron {
327
+ font-size: 11px;
328
+ color: var(--c-text-3);
329
+ transition: transform .2s;
330
+ line-height: 1;
331
+ }
332
+
333
+ .suite--collapsed .suite__chevron { transform: rotate(-90deg); }
334
+
335
+ /* ─── Cases list ─────────────────────────────────────────────────── */
336
+ .suite__cases {
337
+ list-style: none;
338
+ border-top: 1px solid var(--c-border);
339
+ }
340
+
341
+ .suite--collapsed .suite__cases { display: none; }
342
+
343
+ .case {
344
+ display: flex;
345
+ align-items: flex-start;
346
+ gap: 10px;
347
+ padding: 8px 14px 8px 18px;
348
+ }
349
+
350
+ .case + .case { border-top: 1px solid var(--c-border); }
351
+
352
+ .case__icon {
353
+ font-size: 11px;
354
+ font-weight: 700;
355
+ line-height: 1.8;
356
+ flex-shrink: 0;
357
+ width: 14px;
358
+ text-align: center;
359
+ }
360
+
361
+ .case--pass .case__icon { color: var(--c-pass); }
362
+ .case--fail .case__icon { color: var(--c-fail); }
363
+
364
+ .case__body {
365
+ display: flex;
366
+ flex-direction: column;
367
+ gap: 3px;
368
+ flex: 1;
369
+ min-width: 0;
370
+ }
371
+
372
+ .case__name {
373
+ font-size: 13px;
374
+ color: var(--c-text-2);
375
+ }
376
+
377
+ .case--fail .case__name { color: var(--c-text); font-weight: 500; }
378
+
379
+ .case__error {
380
+ display: inline-block;
381
+ font-family: var(--mono);
382
+ font-size: 11px;
383
+ color: var(--c-fail);
384
+ background: var(--c-fail-bg);
385
+ padding: 2px 7px;
386
+ border-radius: var(--radius-xs);
387
+ border-left: 2px solid var(--c-fail);
388
+ word-break: break-all;
389
+ line-height: 1.5;
390
+ }
391
+
392
+ /* ─── Responsive ─────────────────────────────────────────────────── */
393
+
394
+ /* summary 5 列时收窄内间距 */
395
+ @media (max-width: 760px) {
396
+ .summary__group { padding: 12px 6px; }
397
+ .summary__label { font-size: 10px; }
398
+ .summary__value { font-size: 16px; }
399
+ }
400
+
401
+ /* 4 个 tab 在小屏折成 2×2 */
402
+ @media (max-width: 520px) {
403
+ .tabs { flex-wrap: wrap; }
404
+ .tab { flex: 1 1 calc(50% - 4px); }
405
+ }
406
+
407
+ @media (max-width: 600px) {
408
+ .app { padding: 0 12px 48px; }
409
+ .header__title { font-size: 17px; }
410
+ .header__logo { width: 30px; height: 30px; font-size: 11px; }
411
+ .btn-run { padding: 8px 16px; font-size: 13px; }
412
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 创建测试用例运行器
3
+ * @param {string} suiteName - 测试套件名称
4
+ * @returns {{ test, getResults }}
5
+ */
6
+ export function createSuite(suiteName) {
7
+ const results = []
8
+
9
+ function test(caseName, fn) {
10
+ try {
11
+ const result = fn()
12
+ if (result instanceof Promise) {
13
+ return result
14
+ .then(() => {
15
+ results.push({ suite: suiteName, case: caseName, status: 'pass' })
16
+ })
17
+ .catch((err) => {
18
+ results.push({ suite: suiteName, case: caseName, status: 'fail', error: err.message })
19
+ })
20
+ }
21
+ results.push({ suite: suiteName, case: caseName, status: 'pass' })
22
+ } catch (err) {
23
+ results.push({ suite: suiteName, case: caseName, status: 'fail', error: err.message })
24
+ }
25
+ }
26
+
27
+ function assert(condition, msg) {
28
+ if (!condition) throw new Error(msg || '断言失败')
29
+ }
30
+
31
+ function getResults() {
32
+ return results
33
+ }
34
+
35
+ return { test, assert, getResults }
36
+ }
37
+
38
+ /**
39
+ * 打印测试结果到控制台
40
+ * @param {Array} results
41
+ */
42
+ export function printResults(results) {
43
+ let pass = 0
44
+ let fail = 0
45
+ results.forEach((r) => {
46
+ if (r.status === 'pass') {
47
+ pass++
48
+ console.log(` ✓ [${r.suite}] ${r.case}`)
49
+ } else {
50
+ fail++
51
+ console.error(` ✗ [${r.suite}] ${r.case} — ${r.error}`)
52
+ }
53
+ })
54
+ console.log(`\n共 ${results.length} 项,通过 ${pass},失败 ${fail}`)
55
+ }