-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild.cjs
More file actions
148 lines (113 loc) · 5.16 KB
/
build.cjs
File metadata and controls
148 lines (113 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const fs = require('node:fs')
const amaro = require('amaro')
const { gzipSync } = require('node:zlib')
const { execSync } = require('node:child_process')
// ============================================================================
// Compile TypeScript
// ============================================================================
execSync('npx tsc', { stdio: 'inherit' })
execSync('npx tsc -p ./examples/noble-suite', { stdio: 'inherit' })
// ============================================================================
// Process index.js
// ============================================================================
// Transform TypeScript to JavaScript, stripping type annotations only
let js = amaro.transformSync(fs.readFileSync('./index.ts'), { mode: 'strip-only' }).code
fs.writeFileSync('index.js', js)
const indexJsBefore = getFileSizes('index.js')
js = cleanJavaScript(js)
fs.writeFileSync('index.js', js)
const indexJsAfter = getFileSizes('index.js')
printSizes('index.js', indexJsBefore, indexJsAfter)
// Verify that index.js is valid JavaScript by requiring it
try {
require('./index.js')
} catch (cause) {
throw new Error('index.js is not valid javascript', { cause })
}
// ============================================================================
// Process index.d.ts
// ============================================================================
// Verify that index.d.ts and index.d.ts.map exist
if (!fs.existsSync('index.d.ts')) {
throw new Error('index.d.ts not found')
}
if (!fs.existsSync('index.d.ts.map')) {
throw new Error('index.d.ts.map not found')
}
// Clean up TypeScript declaration file
let dts = fs.readFileSync('index.d.ts', 'utf8')
const indexDtsBefore = { uncompressed: dts.length, compressed: gzipSync(dts).length }
// Remove @example blocks including their code samples and the trailing comment line
// Replace with equivalent blank lines to preserve line numbers
dts = dts.replace(/[ \t]*\*[ \t]*@example[\s\S]*?```\n[ \t]*\*[ \t]*\n/g, (match) => {
const lineCount = (match.match(/\n/g) || []).length
return '\n'.repeat(lineCount)
})
fs.writeFileSync('index.d.ts', dts)
const indexDtsAfter = getFileSizes('index.d.ts')
printSizes('index.d.ts', indexDtsBefore, indexDtsAfter)
// ============================================================================
// @panva/hpke-noble
// ============================================================================
{
const inFile = './examples/noble-suite/index.ts'
const outFile = './examples/noble-suite/index.js'
let js = amaro.transformSync(fs.readFileSync(inFile), { mode: 'strip-only' }).code
// Rewrite import paths from '../../index.ts' to 'hpke'
js = js.replace(/(['"])\.\.\/\.\.\/index\.ts\1/g, "'hpke'")
fs.writeFileSync(outFile, js)
const nobleBefore = getFileSizes(outFile)
js = cleanJavaScript(js)
fs.writeFileSync(outFile, js)
const nobleAfter = getFileSizes(outFile)
printSizes('examples/noble-suite/index.js', nobleBefore, nobleAfter)
}
{
const file = './examples/noble-suite/index.d.ts'
let dts = fs.readFileSync(file, 'utf8')
// Rewrite import paths from '../../index.ts' to 'hpke'
dts = dts.replace(/(['"])\.\.\/\.\.\/index\.ts\1/g, "'hpke'")
fs.writeFileSync(file, dts)
}
// ============================================================================
// Utils
// ============================================================================
function cleanJavaScript(code) {
// Replace multi-line JSDoc comment blocks with equivalent blank lines to preserve line numbers
// NOTE: This must run before the inline // comment removal below, because single-line
// /** @see [Name](https://...) */ comments contain // in URLs. If the inline comment
// regex ran first, it would strip everything after the // (including the closing */),
// creating orphaned /** openings that cause the JSDoc regex to swallow subsequent code.
code = code.replace(/^[ \t]*\/\*\*[\s\S]*?\*\/[ \t]*$/gm, (match) => {
const lineCount = (match.match(/\n/g) || []).length
return '\n'.repeat(lineCount)
})
// Remove inline // comments while preserving the code and removing trailing whitespace
code = code.replace(/^(.*)\/\/.*$/gm, (match, code) => {
return code.trimEnd()
})
// Remove coverage ignore directives by replacing them with blank lines
code = code.replace(/^.*\/\*\s*c8\s+ignore\s+next.*$/gm, '')
// Replace lines that only contain whitespace with empty lines
code = code.replace(/^[ \t]+$/gm, '')
return code
}
function getFileSizes(path) {
const content = fs.readFileSync(path)
const uncompressed = content.length
const compressed = gzipSync(content).length
return { uncompressed, compressed }
}
function formatSize(bytes) {
return `${(bytes / 1024).toFixed(2)} KB`
}
function printSizes(label, before, after) {
console.log(`${label}:`)
console.log(
` Uncompressed: ${formatSize(before.uncompressed)} → ${formatSize(after.uncompressed)} (${(((after.uncompressed - before.uncompressed) / before.uncompressed) * 100).toFixed(1)}%)`,
)
console.log(
` Compressed: ${formatSize(before.compressed)} → ${formatSize(after.compressed)} (${(((after.compressed - before.compressed) / before.compressed) * 100).toFixed(1)}%)`,
)
console.log()
}