kn-es-features 1.0.0 → 1.0.2
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/dist/esfeatures.iife.js +11 -14
- package/dist/esfeatures.js +1592 -2278
- package/dist/esfeatures.umd.cjs +11 -14
- package/dist/polyfills.iife.js +7 -7
- package/package.json +7 -3
- package/src/features/es2015/01-let-const.js +0 -33
- package/src/features/es2015/02-arrow-functions.js +0 -56
- package/src/features/es2015/03-template-literals.js +0 -38
- package/src/features/es2015/04-destructuring.js +0 -51
- package/src/features/es2015/05-default-rest-spread.js +0 -74
- package/src/features/es2015/08-symbols.js +0 -71
- package/src/features/es2015/09-iterators-generators.js +0 -71
- package/src/features/es2015/10-map-set.js +1 -86
- package/src/features/es2015/11-proxy-reflect.js +1 -84
- package/src/features/es2015/12-enhanced-objects.js +0 -80
- package/src/features/es2015/16-for-of.js +0 -33
- package/src/features/es2015/17-map.js +0 -46
- package/src/features/es2022/06-regexp-d-flag.js +4 -0
- package/src/features/es2022/07-top-level-await.js +6 -6
- package/src/features/es2025/01-iterator-helpers.js +4 -0
- package/src/features/es2025/02-set-methods.js +5 -1
- package/src/features/es2025/03-promise-try.js +15 -7
- package/src/features/es2025/04-regexp-duplicate-groups.js +4 -0
- package/src/features/es2025/05-uint8array-base64-hex.js +4 -0
- package/src/features/es2025/06-json-parse-source.js +4 -0
- package/src/features/es2025/07-error-is-error.js +4 -0
- package/src/features/es2025/08-float16array.js +4 -8
- package/src/features/es2026/01-math-sum-precise.js +4 -0
- package/src/features/es2026/02-regexp-escape.js +10 -6
- package/src/features/es2026/03-explicit-resource-management.js +5 -1
- package/src/features/es2026/04-atomics-pause.js +4 -0
- package/src/features/es2026/05-import-attributes.js +11 -4
- package/src/polyfills.js +1 -1
- package/src/validate-main.js +223 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validate-main.js —— npm 包校验入口
|
|
3
|
+
*
|
|
4
|
+
* 通过 ESM 命名导入使用 kn-es-features,校验以下内容:
|
|
5
|
+
* 1. 包的 ESM 导出路径可正常解析
|
|
6
|
+
* 2. runAll2015 / runAll2022 / runAll2025 / runAll2026 函数均可调用
|
|
7
|
+
* 3. 返回结果符合预期格式 [{ suite, case, status, error? }]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import 'kn-es-features/polyfills' // 运行时 API 补丁(如 Promise、Symbol)由消费方引入
|
|
12
|
+
import { runAll2015, runAll2022, runAll2025, runAll2026 } from 'kn-es-features/src'
|
|
13
|
+
|
|
14
|
+
/* ── 版本配置 ───────────────────────────────────────────────────── */
|
|
15
|
+
const VERSIONS = [
|
|
16
|
+
{ key: '2015', run: () => runAll2015() },
|
|
17
|
+
{ key: '2022', run: () => runAll2022() },
|
|
18
|
+
{ key: '2025', run: () => runAll2025() },
|
|
19
|
+
{ key: '2026', run: () => runAll2026() },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
/* ── DOM 引用 ────────────────────────────────────────────────────── */
|
|
23
|
+
const btnRun = document.getElementById('btn-run')
|
|
24
|
+
const tabs = document.querySelectorAll('.tab')
|
|
25
|
+
|
|
26
|
+
/* ── Tab 切换 ────────────────────────────────────────────────────── */
|
|
27
|
+
tabs.forEach(tab => {
|
|
28
|
+
tab.addEventListener('click', () => {
|
|
29
|
+
tabs.forEach(t => t.classList.remove('tab--active'))
|
|
30
|
+
tab.classList.add('tab--active')
|
|
31
|
+
document.querySelectorAll('.panel').forEach(p => p.classList.remove('panel--active'))
|
|
32
|
+
document.getElementById(tab.dataset.panel).classList.add('panel--active')
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
/* ── 工具函数 ────────────────────────────────────────────────────── */
|
|
37
|
+
|
|
38
|
+
function escape(str) {
|
|
39
|
+
return String(str)
|
|
40
|
+
.replace(/&/g, '&')
|
|
41
|
+
.replace(/</g, '<')
|
|
42
|
+
.replace(/>/g, '>')
|
|
43
|
+
.replace(/"/g, '"')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function groupBySuite(results) {
|
|
47
|
+
const suites = []
|
|
48
|
+
const map = Object.create(null)
|
|
49
|
+
results.forEach(r => {
|
|
50
|
+
if (!map[r.suite]) {
|
|
51
|
+
const s = { name: r.suite, cases: [] }
|
|
52
|
+
map[r.suite] = s
|
|
53
|
+
suites.push(s)
|
|
54
|
+
}
|
|
55
|
+
map[r.suite].cases.push(r)
|
|
56
|
+
})
|
|
57
|
+
return suites
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function calcStats(results) {
|
|
61
|
+
let pass = 0, fail = 0
|
|
62
|
+
results.forEach(r => r.status === 'pass' ? pass++ : fail++)
|
|
63
|
+
return { pass, fail, total: results.length }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* ── 渲染函数 ────────────────────────────────────────────────────── */
|
|
67
|
+
|
|
68
|
+
function renderCase(c) {
|
|
69
|
+
const li = document.createElement('li')
|
|
70
|
+
li.className = 'case case--' + c.status
|
|
71
|
+
|
|
72
|
+
const icon = document.createElement('span')
|
|
73
|
+
icon.className = 'case__icon'
|
|
74
|
+
icon.textContent = c.status === 'pass' ? '✓' : '✗'
|
|
75
|
+
|
|
76
|
+
const body = document.createElement('span')
|
|
77
|
+
body.className = 'case__body'
|
|
78
|
+
|
|
79
|
+
const name = document.createElement('span')
|
|
80
|
+
name.className = 'case__name'
|
|
81
|
+
name.textContent = c.case
|
|
82
|
+
body.appendChild(name)
|
|
83
|
+
|
|
84
|
+
if (c.error) {
|
|
85
|
+
const err = document.createElement('span')
|
|
86
|
+
err.className = 'case__error'
|
|
87
|
+
err.textContent = c.error
|
|
88
|
+
body.appendChild(err)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
li.appendChild(icon)
|
|
92
|
+
li.appendChild(body)
|
|
93
|
+
return li
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function renderSuite(suite, index) {
|
|
97
|
+
let pass = 0, fail = 0
|
|
98
|
+
suite.cases.forEach(c => c.status === 'pass' ? pass++ : fail++)
|
|
99
|
+
const stateKey = fail === 0 ? 'pass' : 'fail'
|
|
100
|
+
|
|
101
|
+
const card = document.createElement('div')
|
|
102
|
+
card.className = 'suite'
|
|
103
|
+
|
|
104
|
+
const header = document.createElement('div')
|
|
105
|
+
header.className = 'suite__header'
|
|
106
|
+
header.innerHTML =
|
|
107
|
+
'<div class="suite__header-left">' +
|
|
108
|
+
'<span class="suite__indicator suite__indicator--' + stateKey + '"></span>' +
|
|
109
|
+
'<span class="suite__name">' + (index + 1) + ' - ' + escape(suite.name) + '</span>' +
|
|
110
|
+
'</div>' +
|
|
111
|
+
'<div class="suite__header-right">' +
|
|
112
|
+
'<span class="suite__stat suite__stat--' + stateKey + '">' +
|
|
113
|
+
pass + ' / ' + suite.cases.length +
|
|
114
|
+
'</span>' +
|
|
115
|
+
'<span class="suite__chevron">▾</span>' +
|
|
116
|
+
'</div>'
|
|
117
|
+
|
|
118
|
+
header.addEventListener('click', () => card.classList.toggle('suite--collapsed'))
|
|
119
|
+
|
|
120
|
+
const ul = document.createElement('ul')
|
|
121
|
+
ul.className = 'suite__cases'
|
|
122
|
+
suite.cases.forEach(c => ul.appendChild(renderCase(c)))
|
|
123
|
+
|
|
124
|
+
card.appendChild(header)
|
|
125
|
+
card.appendChild(ul)
|
|
126
|
+
return card
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function showLoader(panel) {
|
|
130
|
+
panel.innerHTML =
|
|
131
|
+
'<div class="loader">' +
|
|
132
|
+
'<span class="loader__spinner"></span>' +
|
|
133
|
+
'<span>正在运行测试…</span>' +
|
|
134
|
+
'</div>'
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function renderPanel(panel, results) {
|
|
138
|
+
panel.innerHTML = ''
|
|
139
|
+
if (!results || results.length === 0) {
|
|
140
|
+
panel.innerHTML =
|
|
141
|
+
'<div class="placeholder">' +
|
|
142
|
+
'<span class="placeholder__icon">📭</span>' +
|
|
143
|
+
'<p class="placeholder__text">暂无测试结果</p>' +
|
|
144
|
+
'</div>'
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
const frag = document.createDocumentFragment()
|
|
148
|
+
groupBySuite(results).forEach((s,index) => frag.appendChild(renderSuite(s,index)))
|
|
149
|
+
panel.appendChild(frag)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function updateSummaryValue(id, stats) {
|
|
153
|
+
const el = document.getElementById('val-' + id)
|
|
154
|
+
if (!el) return
|
|
155
|
+
if (!stats) { el.textContent = '—'; el.className = 'summary__value'; return }
|
|
156
|
+
el.textContent = stats.pass + ' / ' + stats.total
|
|
157
|
+
el.className = 'summary__value summary__value--' + (stats.fail === 0 ? 'pass' : 'fail')
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function updateTabBadge(id, stats) {
|
|
161
|
+
const el = document.getElementById('badge-' + id)
|
|
162
|
+
if (!el) return
|
|
163
|
+
if (!stats) { el.textContent = ''; el.className = 'tab__badge'; return }
|
|
164
|
+
if (stats.fail === 0) {
|
|
165
|
+
el.textContent = '全部通过'
|
|
166
|
+
el.className = 'tab__badge tab__badge--pass'
|
|
167
|
+
} else {
|
|
168
|
+
el.textContent = stats.fail + ' 失败'
|
|
169
|
+
el.className = 'tab__badge tab__badge--fail'
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* ── 主运行流程 ──────────────────────────────────────────────────── */
|
|
174
|
+
async function runTests() {
|
|
175
|
+
btnRun.disabled = true
|
|
176
|
+
btnRun.classList.add('btn-run--running')
|
|
177
|
+
btnRun.querySelector('.btn-run__label').textContent = '运行中…'
|
|
178
|
+
|
|
179
|
+
VERSIONS.forEach(v => {
|
|
180
|
+
updateSummaryValue(v.key, null)
|
|
181
|
+
updateTabBadge(v.key, null)
|
|
182
|
+
showLoader(document.getElementById('panel-' + v.key))
|
|
183
|
+
})
|
|
184
|
+
updateSummaryValue('total', null)
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const resultSets = await Promise.all(VERSIONS.map(v => v.run()))
|
|
188
|
+
|
|
189
|
+
let totalPass = 0, totalFail = 0, totalCount = 0
|
|
190
|
+
|
|
191
|
+
VERSIONS.forEach((v, i) => {
|
|
192
|
+
const results = resultSets[i]
|
|
193
|
+
const stats = calcStats(results)
|
|
194
|
+
renderPanel(document.getElementById('panel-' + v.key), results)
|
|
195
|
+
updateSummaryValue(v.key, stats)
|
|
196
|
+
updateTabBadge(v.key, stats)
|
|
197
|
+
totalPass += stats.pass
|
|
198
|
+
totalFail += stats.fail
|
|
199
|
+
totalCount += stats.total
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
updateSummaryValue('total', { pass: totalPass, fail: totalFail, total: totalCount })
|
|
203
|
+
|
|
204
|
+
} catch (err) {
|
|
205
|
+
VERSIONS.forEach(v => {
|
|
206
|
+
const panel = document.getElementById('panel-' + v.key)
|
|
207
|
+
if (panel) {
|
|
208
|
+
panel.innerHTML =
|
|
209
|
+
'<div class="placeholder">' +
|
|
210
|
+
'<span class="placeholder__icon">⚠️</span>' +
|
|
211
|
+
'<p class="placeholder__text">运行出错:' + escape(err.message) + '</p>' +
|
|
212
|
+
'</div>'
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
console.error('[kn-es-features 校验]', err)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
btnRun.disabled = false
|
|
219
|
+
btnRun.classList.remove('btn-run--running')
|
|
220
|
+
btnRun.querySelector('.btn-run__label').textContent = '重新运行'
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
btnRun.addEventListener('click', runTests)
|