forked from brianc/node-postgres
-
Notifications
You must be signed in to change notification settings - Fork 0
/
remove-public-const-enum.js
120 lines (104 loc) · 3.93 KB
/
remove-public-const-enum.js
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
// This task would be better served by recast or something like that.
// https://github.com/travellocal/babel-plugin-declare-const-enum is a good starting point for that.
const fs = require('fs')
const path = require('path')
const PATCH_SOURCE = process.argv.slice(2).indexOf('--src') >= 0
const filepath = path.join(__dirname, PATCH_SOURCE ? '../src/messages.ts' : '../dist/messages.d.ts')
const backuppath = path.join(
__dirname,
PATCH_SOURCE ? '../src/messages.const-enum.ts' : '../dist/messages.const-enum.d.ts'
)
const otherfiles = ['../src/parser.ts']
/** @type {string} */
let srcpath
if (PATCH_SOURCE) {
srcpath = filepath
} else {
// use the filepath if it's newer
try {
const backupStat = fs.statSync(backuppath)
const fileStat = fs.statSync(filepath)
srcpath = fileStat.mtimeMs > backupStat.mtimeMs ? filepath : backuppath
} catch (err) {
if (err.code !== 'ENOENT') {
throw err
}
srcpath = filepath
}
}
const src = fs.readFileSync(srcpath, 'utf8')
/** @type {({startIndex: number, endIndex: number, content: string})[]} */
let replacements = []
// find the const enum declarations
const startRe = PATCH_SOURCE
? /(^|\n)export const enum ([A-Za-z][A-Za-z0-9]+) \{\n*/g
: /(^|\n)export declare const enum ([A-Za-z][A-Za-z0-9]+) \{\n*/g
const endRe = /\n\}/g
const constEnums = {}
/** @type {RegExpExecArray | null} */
let match
while ((match = startRe.exec(src))) {
const startIndex = match.index
const name = match[2]
const contentStartIndex = (endRe.lastIndex = startRe.lastIndex)
const end = endRe.exec(src)
if (!end) break
const contentEndIndex = end.index
const endIndex = (startRe.lastIndex = endRe.lastIndex)
// collect the members of the const enum
const constEnumContent = src.slice(contentStartIndex, contentEndIndex)
const itemRe = /\b([A-Za-z][A-Za-z0-9]+)\s*=\s*(.+),/g
const lastRe = /\b([A-Za-z][A-Za-z0-9]+)\s*=\s*(.+)/g
const enumItems = (constEnums[name] = {})
const enumValueLiterals = []
/** @type {RegExpExecArray | null} */
let itemMatch
while ((itemMatch = itemRe.exec(constEnumContent))) {
enumValueLiterals.push((enumItems[itemMatch[1]] = itemMatch[2]))
lastRe.lastIndex = itemRe.lastIndex
}
itemMatch = lastRe.exec(constEnumContent)
if (itemMatch) {
enumValueLiterals.push((enumItems[itemMatch[1]] = itemMatch[2]))
}
replacements.push({
startIndex,
endIndex,
content: `${match[1]}export type ${name} =\n${enumValueLiterals.map((s) => ` | ${s}`).join('\n')};`,
})
}
if (replacements.length > 0) {
// replace the const enum declarations with a literal type union
let out = replacements
.sort((a, b) => a.startIndex - b.startIndex)
.reduce((out, { endIndex, content }, i, r) => {
const next = r[i + 1]
return out + content + src.slice(endIndex, next && next.startIndex)
}, src.slice(0, replacements[0].startIndex))
// replace references to the enum with the literals
for (const enumName of Object.keys(constEnums)) {
const enumItems = constEnums[enumName]
const re = new RegExp(`\\b${enumName}\\.(${Object.keys(enumItems).join('|')})\\b`, 'g')
out = out.replace(re, (s, enumItemName) => enumItems[enumItemName])
}
if (!PATCH_SOURCE && srcpath === filepath) {
fs.writeFileSync(backuppath, src, 'utf8')
}
fs.writeFileSync(filepath, out, 'utf8')
if (!PATCH_SOURCE) {
const now = new Date()
fs.utimesSync(backuppath, now, now)
} else {
for (const f of otherfiles) {
const otherfile = path.join(__dirname, f)
let otherOut = fs.readFileSync(otherfile, 'utf8')
// replace references to the enum with the literals
for (const enumName of Object.keys(constEnums)) {
const enumItems = constEnums[enumName]
const re = new RegExp(`\\b${enumName}\\.(${Object.keys(enumItems).join('|')})\\b`, 'g')
otherOut = otherOut.replace(re, (s, enumItemName) => enumItems[enumItemName])
}
fs.writeFileSync(otherfile, otherOut, 'utf8')
}
}
}