/
js_table.ts
147 lines (116 loc) · 4.4 KB
/
js_table.ts
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
// This file generates "internal/compat/js_table.go"
import fs = require('fs')
import { Engine, JSFeature, VersionRange, VersionRangeMap, engines } from './index'
const jsFeatureString = (feature: string): string => {
return feature.replace(/([A-Z])/g, '-$1').slice(1).toLowerCase()
}
const simpleMap = (entries: [string, string][]) => {
let maxLength = 0
for (const [key] of entries) {
maxLength = Math.max(maxLength, key.length + 1)
}
return entries.map(([key, value]) => `\t${(key + ':').padEnd(maxLength)} ${value},`).join('\n')
}
const compareEngines = (a: Engine, b: Engine): number => {
const lowerA = a.toLowerCase()
const lowerB = b.toLowerCase()
return lowerA < lowerB ? -1 : lowerA > lowerB ? 1 : 0
}
const jsTableMap = (map: Partial<Record<Engine, VersionRange[]>>) => {
const engineKeys = (Object.keys(map) as Engine[]).sort(compareEngines)
const maxLength = engineKeys.reduce((a, b) => Math.max(a, b.length + 1), 0)
if (engineKeys.length === 0) return '{}'
return `{\n${engineKeys.map(engine => {
const items = map[engine]!.map(range => {
return `{start: v{${range.start.concat(0, 0).slice(0, 3).join(', ')
}}${range.end ? `, end: v{${range.end.concat(0, 0).slice(0, 3).join(', ')}}` : ''}}`
})
return `\t\t${(engine + ':').padEnd(maxLength)} {${items.join(', ')}},`
}).join('\n')}\n\t}`
}
const jsTableValidEnginesMap = (engines: Engine[]) => {
const maxLength = engines.reduce((a, b) => Math.max(a, b.length + 4), 0)
if (engines.length === 0) return '{}'
return engines.map(engine => {
return `\t${`"${engine.toLowerCase()}": `.padEnd(maxLength)}api.Engine${engine},`
}).join('\n')
}
const generatedByComment = `// This file was automatically generated by "js_table.ts"`
export const generateTableForJS = (map: VersionRangeMap<JSFeature>): void => {
const enginesKeys = (Object.keys(engines) as Engine[]).sort(compareEngines)
fs.writeFileSync(__dirname + '/../internal/compat/js_table.go',
`${generatedByComment}
package compat
type Engine uint8
const (
${enginesKeys.map((engine, i) => `\t${engine}${i ? '' : ' Engine = iota'}`).join('\n')}
)
func (e Engine) String() string {
\tswitch e {
${enginesKeys.map(engine => `\tcase ${engine}:\n\t\treturn "${engine.toLowerCase()}"`).join('\n')}
\t}
\treturn ""
}
func (e Engine) IsBrowser() bool {
\tswitch e {
\tcase Chrome, Edge, Firefox, IE, IOS, Opera, Safari:
\t\treturn true
\t}
\treturn false
}
type JSFeature uint64
const (
${Object.keys(map).sort().map((feature, i) => `\t${feature}${i ? '' : ' JSFeature = 1 << iota'}`).join('\n')}
)
var StringToJSFeature = map[string]JSFeature{
${simpleMap(Object.keys(map).sort().map(feature => [`"${jsFeatureString(feature)}"`, feature]))}
}
func (features JSFeature) Has(feature JSFeature) bool {
\treturn (features & feature) != 0
}
func (features JSFeature) ApplyOverrides(overrides JSFeature, mask JSFeature) JSFeature {
\treturn (features & ^mask) | (overrides & mask)
}
var jsTable = map[JSFeature]map[Engine][]versionRange{
${Object.keys(map).sort().map(feature => `\t${feature}: ${jsTableMap(map[feature as JSFeature]!)},`).join('\n')}
}
// Return all features that are not available in at least one environment
func UnsupportedJSFeatures(constraints map[Engine]Semver) (unsupported JSFeature) {
\tfor feature, engines := range jsTable {
\t\tif feature == InlineScript {
\t\t\tcontinue // This is purely user-specified
\t\t}
\t\tfor engine, version := range constraints {
\t\t\tif versionRanges, ok := engines[engine]; !ok || !isVersionSupported(versionRanges, version) {
\t\t\t\tunsupported |= feature
\t\t\t}
\t\t}
\t}
\treturn
}
`)
fs.writeFileSync(__dirname + '/../pkg/api/api_js_table.go',
`${generatedByComment}
package api
import "github.com/evanw/esbuild/internal/compat"
type EngineName uint8
const (
${enginesKeys.filter(engine => engine !== 'ES').map((engine, i) => `\tEngine${engine}${i ? '' : ' EngineName = iota'}`).join('\n')}
)
func convertEngineName(engine EngineName) compat.Engine {
\tswitch engine {
${enginesKeys.filter(engine => engine !== 'ES').map(engine => `\tcase Engine${engine}:\n\t\treturn compat.${engine}`).join('\n')}
\tdefault:
\t\tpanic("Invalid engine name")
\t}
}
`)
fs.writeFileSync(__dirname + '/../pkg/cli/cli_js_table.go',
`${generatedByComment}
package cli
import "github.com/evanw/esbuild/pkg/api"
var validEngines = map[string]api.EngineName{
${jsTableValidEnginesMap(enginesKeys.filter(engine => engine !== 'ES'))}
}
`)
}