Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 034a05e

Browse files
committedSep 26, 2023
feat: use enum to replace const enum
1 parent b8fc18c commit 034a05e

35 files changed

+150
-124
lines changed
 

‎.eslintrc.cjs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
const DOMGlobals = ['window', 'document']
22
const NodeGlobals = ['module', 'require']
33

4+
const banConstEnum = {
5+
selector: 'TSEnumDeclaration[const=true]',
6+
message: 'Please use enums, instead',
7+
}
8+
9+
/**
10+
* @type {import('eslint-define-config').ESLintConfig}
11+
*/
412
module.exports = {
513
parser: '@typescript-eslint/parser',
614
parserOptions: {
@@ -20,6 +28,7 @@ module.exports = {
2028

2129
'no-restricted-syntax': [
2230
'error',
31+
banConstEnum,
2332
// since we target ES2015 for baseline support, we need to forbid object
2433
// rest spread usage in destructure as it compiles into a verbose helper.
2534
'ObjectPattern > RestElement',
@@ -61,23 +70,32 @@ module.exports = {
6170
],
6271
rules: {
6372
'no-restricted-globals': ['error', ...DOMGlobals],
64-
'no-restricted-syntax': 'off'
73+
'no-restricted-syntax': [
74+
'error',
75+
banConstEnum,
76+
]
6577
}
6678
},
6779
// Private package, browser only + no syntax restrictions
6880
{
6981
files: ['packages/template-explorer/**', 'packages/sfc-playground/**'],
7082
rules: {
7183
'no-restricted-globals': ['error', ...NodeGlobals],
72-
'no-restricted-syntax': 'off'
84+
'no-restricted-syntax': [
85+
'error',
86+
banConstEnum,
87+
]
7388
}
7489
},
7590
// Node scripts
7691
{
7792
files: ['scripts/**', '*.{js,ts}', 'packages/**/index.js'],
7893
rules: {
7994
'no-restricted-globals': 'off',
80-
'no-restricted-syntax': 'off'
95+
'no-restricted-syntax': [
96+
'error',
97+
banConstEnum,
98+
]
8199
}
82100
}
83101
]

‎package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"esbuild": "^0.19.3",
7777
"esbuild-plugin-polyfill-node": "^0.3.0",
7878
"eslint": "^8.49.0",
79+
"eslint-define-config": "^1.23.0",
7980
"eslint-plugin-jest": "^27.4.0",
8081
"estree-walker": "^2.0.2",
8182
"execa": "^8.0.1",

‎packages/compiler-core/src/ast.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ import { ImportItem, TransformContext } from './transform'
2121
// compilers.
2222
export type Namespace = number
2323

24-
export const enum Namespaces {
24+
export enum Namespaces {
2525
HTML
2626
}
2727

28-
export const enum NodeTypes {
28+
export enum NodeTypes {
2929
ROOT,
3030
ELEMENT,
3131
TEXT,
@@ -59,7 +59,7 @@ export const enum NodeTypes {
5959
JS_RETURN_STATEMENT
6060
}
6161

62-
export const enum ElementTypes {
62+
export enum ElementTypes {
6363
ELEMENT,
6464
COMPONENT,
6565
SLOT,
@@ -202,7 +202,7 @@ export interface DirectiveNode extends Node {
202202
* Higher levels implies lower levels. e.g. a node that can be stringified
203203
* can always be hoisted and skipped for patch.
204204
*/
205-
export const enum ConstantTypes {
205+
export enum ConstantTypes {
206206
NOT_CONSTANT = 0,
207207
CAN_SKIP_PATCH,
208208
CAN_HOIST,

‎packages/compiler-core/src/compat/compatConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface CompilerCompatOptions {
1313
compatConfig?: CompilerCompatConfig
1414
}
1515

16-
export const enum CompilerDeprecationTypes {
16+
export enum CompilerDeprecationTypes {
1717
COMPILER_IS_ON_ELEMENT = 'COMPILER_IS_ON_ELEMENT',
1818
COMPILER_V_BIND_SYNC = 'COMPILER_V_BIND_SYNC',
1919
COMPILER_V_BIND_PROP = 'COMPILER_V_BIND_PROP',

‎packages/compiler-core/src/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function createCompilerError<T extends number>(
3737
return error
3838
}
3939

40-
export const enum ErrorCodes {
40+
export enum ErrorCodes {
4141
// parse errors
4242
ABRUPT_CLOSING_OF_EMPTY_COMMENT,
4343
CDATA_IN_HTML_CONTENT,

‎packages/compiler-core/src/options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export type HoistTransform = (
7373
parent: ParentNode
7474
) => void
7575

76-
export const enum BindingTypes {
76+
export enum BindingTypes {
7777
/**
7878
* returned from data()
7979
*/

‎packages/compiler-core/src/parse.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export const defaultParserOptions: MergedParserOptions = {
8080
comments: __DEV__
8181
}
8282

83-
export const enum TextModes {
83+
export enum TextModes {
8484
// | Elements | Entities | End sign | Inside of
8585
DATA, // | ✔ | ✔ | End tags of ancestors |
8686
RCDATA, // | ✘ | ✔ | End tag of the parent | <textarea>
@@ -502,7 +502,7 @@ function parseElement(
502502
return element
503503
}
504504

505-
const enum TagType {
505+
enum TagType {
506506
Start,
507507
End
508508
}

‎packages/compiler-core/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const nonIdentifierRE = /^\d|[^\$\w]/
6464
export const isSimpleIdentifier = (name: string): boolean =>
6565
!nonIdentifierRE.test(name)
6666

67-
const enum MemberExpLexState {
67+
enum MemberExpLexState {
6868
inMemberExp,
6969
inBrackets,
7070
inParens,

‎packages/compiler-dom/src/errors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function createDOMCompilerError(
2020
) as DOMCompilerError
2121
}
2222

23-
export const enum DOMErrorCodes {
23+
export enum DOMErrorCodes {
2424
X_V_HTML_NO_EXPRESSION = 53 /* ErrorCodes.__EXTEND_POINT__ */,
2525
X_V_HTML_WITH_CHILDREN,
2626
X_V_TEXT_NO_EXPRESSION,
@@ -36,7 +36,7 @@ export const enum DOMErrorCodes {
3636
}
3737

3838
if (__TEST__) {
39-
// esbuild cannot infer const enum increments if first value is from another
39+
// esbuild cannot infer enum increments if first value is from another
4040
// file, so we have to manually keep them in sync. this check ensures it
4141
// errors out if there are collisions.
4242
if (DOMErrorCodes.X_V_HTML_NO_EXPRESSION < ErrorCodes.__EXTEND_POINT__) {

‎packages/compiler-dom/src/parserOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const isRawTextContainer = /*#__PURE__*/ makeMap(
1515
true
1616
)
1717

18-
export const enum DOMNamespaces {
18+
export enum DOMNamespaces {
1919
HTML = 0 /* Namespaces.HTML */,
2020
SVG,
2121
MATH_ML

‎packages/compiler-dom/src/transforms/stringifyStatic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
} from '@vue/shared'
3434
import { DOMNamespaces } from '../parserOptions'
3535

36-
export const enum StringifyThresholds {
36+
export enum StringifyThresholds {
3737
ELEMENT_WITH_BINDING_COUNT = 5,
3838
NODE_COUNT = 20
3939
}

‎packages/compiler-sfc/src/style/cssVars.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function parseCssVars(sfc: SFCDescriptor): string[] {
7070
return vars
7171
}
7272

73-
const enum LexerState {
73+
enum LexerState {
7474
inParens,
7575
inSingleQuoteString,
7676
inDoubleQuoteString

‎packages/compiler-ssr/src/errors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ export function createSSRCompilerError(
1616
return createCompilerError(code, loc, SSRErrorMessages) as SSRCompilerError
1717
}
1818

19-
export const enum SSRErrorCodes {
19+
export enum SSRErrorCodes {
2020
X_SSR_UNSAFE_ATTR_NAME = 65 /* DOMErrorCodes.__EXTEND_POINT__ */,
2121
X_SSR_NO_TELEPORT_TARGET,
2222
X_SSR_INVALID_AST_NODE
2323
}
2424

2525
if (__TEST__) {
26-
// esbuild cannot infer const enum increments if first value is from another
26+
// esbuild cannot infer enum increments if first value is from another
2727
// file, so we have to manually keep them in sync. this check ensures it
2828
// errors out if there are collisions.
2929
if (SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME < DOMErrorCodes.__EXTEND_POINT__) {

‎packages/reactivity/src/index.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export {
3131
shallowReadonly,
3232
markRaw,
3333
toRaw,
34-
ReactiveFlags /* @remove */,
34+
ReactiveFlags,
3535
type Raw,
3636
type DeepReadonly,
3737
type ShallowReactive,
@@ -69,7 +69,4 @@ export {
6969
getCurrentScope,
7070
onScopeDispose
7171
} from './effectScope'
72-
export {
73-
TrackOpTypes /* @remove */,
74-
TriggerOpTypes /* @remove */
75-
} from './operations'
72+
export { TrackOpTypes, TriggerOpTypes } from './operations'

‎packages/reactivity/src/operations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// using literal strings instead of numbers so that it's easier to inspect
22
// debugger events
33

4-
export const enum TrackOpTypes {
4+
export enum TrackOpTypes {
55
GET = 'get',
66
HAS = 'has',
77
ITERATE = 'iterate'
88
}
99

10-
export const enum TriggerOpTypes {
10+
export enum TriggerOpTypes {
1111
SET = 'set',
1212
ADD = 'add',
1313
DELETE = 'delete',

‎packages/reactivity/src/reactive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from './collectionHandlers'
1414
import type { UnwrapRefSimple, Ref, RawSymbol } from './ref'
1515

16-
export const enum ReactiveFlags {
16+
export enum ReactiveFlags {
1717
SKIP = '__v_skip',
1818
IS_REACTIVE = '__v_isReactive',
1919
IS_READONLY = '__v_isReadonly',
@@ -34,7 +34,7 @@ export const shallowReactiveMap = new WeakMap<Target, any>()
3434
export const readonlyMap = new WeakMap<Target, any>()
3535
export const shallowReadonlyMap = new WeakMap<Target, any>()
3636

37-
const enum TargetType {
37+
enum TargetType {
3838
INVALID = 0,
3939
COMMON = 1,
4040
COLLECTION = 2

‎packages/runtime-core/src/compat/compatConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from '../component'
1111
import { warn } from '../warning'
1212

13-
export const enum DeprecationTypes {
13+
export enum DeprecationTypes {
1414
GLOBAL_MOUNT = 'GLOBAL_MOUNT',
1515
GLOBAL_MOUNT_CONTAINER = 'GLOBAL_MOUNT_CONTAINER',
1616
GLOBAL_EXTEND = 'GLOBAL_EXTEND',

‎packages/runtime-core/src/componentOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ export type OptionTypesType<
586586
Defaults: Defaults
587587
}
588588

589-
const enum OptionTypes {
589+
enum OptionTypes {
590590
PROPS = 'Props',
591591
DATA = 'Data',
592592
COMPUTED = 'Computed',

‎packages/runtime-core/src/componentProps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export type ExtractPublicPropTypes<O> = {
164164
[K in keyof Pick<O, PublicOptionalKeys<O>>]?: InferPropType<O[K]>
165165
}
166166

167-
const enum BooleanFlags {
167+
enum BooleanFlags {
168168
shouldCast,
169169
shouldCastTrue
170170
}

‎packages/runtime-core/src/componentPublicInstance.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ if (__COMPAT__) {
278278
installCompatInstanceProperties(publicPropertiesMap)
279279
}
280280

281-
const enum AccessTypes {
281+
enum AccessTypes {
282282
OTHER,
283283
SETUP,
284284
DATA,

‎packages/runtime-core/src/components/Teleport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ export const TeleportImpl = {
269269
hydrate: hydrateTeleport
270270
}
271271

272-
export const enum TeleportMoveTypes {
272+
export enum TeleportMoveTypes {
273273
TARGET_CHANGE,
274274
TOGGLE, // enable / disable
275275
REORDER // moved in the main view

‎packages/runtime-core/src/devtools.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface AppRecord {
1010
types: Record<string, string | Symbol>
1111
}
1212

13-
const enum DevtoolsHooks {
13+
enum DevtoolsHooks {
1414
APP_INIT = 'app:init',
1515
APP_UNMOUNT = 'app:unmount',
1616
COMPONENT_UPDATED = 'component:updated',

‎packages/runtime-core/src/enums.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const enum LifecycleHooks {
1+
export enum LifecycleHooks {
22
BEFORE_CREATE = 'bc',
33
CREATED = 'c',
44
BEFORE_MOUNT = 'bm',

‎packages/runtime-core/src/errorHandling.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { LifecycleHooks } from './enums'
66

77
// contexts where user provided function may be executed, in addition to
88
// lifecycle hooks.
9-
export const enum ErrorCodes {
9+
export enum ErrorCodes {
1010
SETUP_FUNCTION,
1111
RENDER_FUNCTION,
1212
WATCH_GETTER,

‎packages/runtime-core/src/hydration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export type RootHydrateFunction = (
3030
container: (Element | ShadowRoot) & { _vnode?: VNode }
3131
) => void
3232

33-
const enum DOMNodeTypes {
33+
enum DOMNodeTypes {
3434
ELEMENT = 1,
3535
TEXT = 3,
3636
COMMENT = 8

‎packages/runtime-core/src/renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export type SetupRenderEffectFn = (
264264
optimized: boolean
265265
) => void
266266

267-
export const enum MoveType {
267+
export enum MoveType {
268268
ENTER,
269269
LEAVE,
270270
REORDER

‎packages/runtime-test/src/nodeOps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { markRaw } from '@vue/reactivity'
22

3-
export const enum TestNodeTypes {
3+
export enum TestNodeTypes {
44
TEXT = 'text',
55
ELEMENT = 'element',
66
COMMENT = 'comment'
77
}
88

9-
export const enum NodeOpTypes {
9+
export enum NodeOpTypes {
1010
CREATE = 'create',
1111
INSERT = 'insert',
1212
REMOVE = 'remove',

‎packages/shared/src/patchFlags.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* Check the `patchElement` function in '../../runtime-core/src/renderer.ts' to see how the
1717
* flags are handled during diff.
1818
*/
19-
export const enum PatchFlags {
19+
export enum PatchFlags {
2020
/**
2121
* Indicates an element with dynamic textContent (children fast path)
2222
*/

‎packages/shared/src/shapeFlags.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const enum ShapeFlags {
1+
export enum ShapeFlags {
22
ELEMENT = 1,
33
FUNCTIONAL_COMPONENT = 1 << 1,
44
STATEFUL_COMPONENT = 1 << 2,

‎packages/shared/src/slotFlags.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const enum SlotFlags {
1+
export enum SlotFlags {
22
/**
33
* Stable slots that only reference slot props or context state. The slot
44
* can fully capture its own dependencies so when passed down the parent won't

‎packages/vue/macros.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010

1111
export declare const RefType: unique symbol
1212

13-
export declare const enum RefTypes {
13+
export declare enum RefTypes {
1414
Ref = 1,
1515
ComputedRef = 2,
1616
WritableComputedRef = 3

‎pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎rollup.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import terser from '@rollup/plugin-terser'
1212
import esbuild from 'rollup-plugin-esbuild'
1313
import alias from '@rollup/plugin-alias'
1414
import { entries } from './scripts/aliases.js'
15-
import { constEnum } from './scripts/const-enum.js'
15+
import { simplifyEnum } from './scripts/simplify-enum.js'
1616

1717
if (!process.env.TARGET) {
1818
throw new Error('TARGET package must be specified via --environment flag.')
@@ -32,7 +32,7 @@ const pkg = require(resolve(`package.json`))
3232
const packageOptions = pkg.buildOptions || {}
3333
const name = packageOptions.filename || path.basename(packageDir)
3434

35-
const [enumPlugin, enumDefines] = constEnum()
35+
const [enumPlugin, enumDefines] = simplifyEnum()
3636

3737
const outputConfigs = {
3838
'esm-bundler': {

‎scripts/build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { execa, execaSync } from 'execa'
2626
import { cpus } from 'node:os'
2727
import { createRequire } from 'node:module'
2828
import { targets as allTargets, fuzzyMatchTarget } from './utils.js'
29-
import { scanEnums } from './const-enum.js'
29+
import { scanEnums } from './simplify-enum.js'
3030
import prettyBytes from 'pretty-bytes'
3131

3232
const require = createRequire(import.meta.url)

‎scripts/const-enum.js renamed to ‎scripts/simplify-enum.js

Lines changed: 78 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
/**
44
* We use rollup-plugin-esbuild for faster builds, but esbuild in isolation
5-
* mode compiles const enums into runtime enums, bloating bundle size.
5+
* mode compiles enums into runtime enums, bloating bundle size.
66
*
7-
* Here we pre-process all the const enums in the project and turn them into
7+
* Here we pre-process all the enums in the project and turn them into
88
* global replacements, and remove the original declarations and re-exports.
99
*
10-
* This erases the const enums before the esbuild transform so that we can
10+
* This erases the enums before the esbuild transform so that we can
1111
* leverage esbuild's speed while retaining the DX and bundle size benefits
12-
* of const enums.
12+
* of enums.
1313
*
1414
* This file is expected to be executed with project root as cwd.
1515
*/
@@ -26,26 +26,32 @@ import { parse } from '@babel/parser'
2626
import path from 'node:path'
2727
import MagicString from 'magic-string'
2828

29+
/**
30+
* @typedef {{ id: string, range: [start: number, end: number], members: Array<{ name: string, value: string | number }>}} EnumDeclaration
31+
* @typedef {{ declarations: { [file: string] : Array<EnumDeclaration>}, defines: { [ id_key: `${string}.${string}`]: string } }} EnumData
32+
*/
33+
2934
const ENUM_CACHE_PATH = 'temp/enum.json'
3035

36+
/**
37+
* @param {string} exp
38+
* @returns {string | number}
39+
*/
3140
function evaluate(exp) {
3241
return new Function(`return ${exp}`)()
3342
}
3443

3544
// this is called in the build script entry once
3645
// so the data can be shared across concurrent Rollup processes
3746
export function scanEnums() {
38-
/**
39-
* @type {{ ranges: Record<string, [number, number][]>, defines: Record<string, string>, ids: string[] }}
40-
*/
47+
/** @type {EnumData} */
4148
const enumData = {
42-
ranges: {},
43-
defines: {},
44-
ids: []
49+
declarations: {},
50+
defines: {}
4551
}
4652

47-
// 1. grep for files with exported const enum
48-
const { stdout } = execaSync('git', ['grep', `export const enum`])
53+
// 1. grep for files with exported enum
54+
const { stdout } = execaSync('git', ['grep', `export enum`])
4955
const files = [...new Set(stdout.split('\n').map(line => line.split(':')[0]))]
5056

5157
// 2. parse matched files to collect enum info
@@ -63,32 +69,35 @@ export function scanEnums() {
6369
node.declaration &&
6470
node.declaration.type === 'TSEnumDeclaration'
6571
) {
66-
if (file in enumData.ranges) {
67-
// @ts-ignore
68-
enumData.ranges[file].push([node.start, node.end])
69-
} else {
70-
// @ts-ignore
71-
enumData.ranges[file] = [[node.start, node.end]]
72-
}
73-
7472
const decl = node.declaration
73+
const id = decl.id.name
74+
/** @type {string | number | undefined} */
7575
let lastInitialized
76+
77+
/** @type {EnumDeclaration} */
78+
const declaration = {
79+
id,
80+
range: [node.start ?? -1, node.end ?? -1],
81+
members: []
82+
}
83+
7684
for (let i = 0; i < decl.members.length; i++) {
7785
const e = decl.members[i]
78-
const id = decl.id.name
79-
if (!enumData.ids.includes(id)) {
80-
enumData.ids.push(id)
81-
}
8286
const key = e.id.type === 'Identifier' ? e.id.name : e.id.value
83-
const fullKey = `${id}.${key}`
84-
const saveValue = value => {
87+
const fullKey = /** @type {const} */ (`${id}.${key}`)
88+
const saveValue = (/** @type {string | number} */ value) => {
89+
// We need allow same name enum in different file.
90+
// For example: enum ErrorCodes exist in both @vue/compiler-core and @vue/runtime-core
91+
// But not allow `ErrorCodes.__EXTEND_POINT__` appear in two same name enum
8592
if (fullKey in enumData.defines) {
8693
throw new Error(`name conflict for enum ${id} in ${file}`)
8794
}
8895
enumData.defines[fullKey] = JSON.stringify(value)
96+
declaration.members.push({ name: key, value })
8997
}
9098
const init = e.initializer
9199
if (init) {
100+
/** @type {string | number | undefined} */
92101
let value
93102
if (
94103
init.type === 'StringLiteral' ||
@@ -99,14 +108,16 @@ export function scanEnums() {
99108

100109
// e.g. 1 << 2
101110
if (init.type === 'BinaryExpression') {
102-
const resolveValue = node => {
111+
const resolveValue = (
112+
/** @type {import('@babel/types').Expression | import('@babel/types').PrivateName} */ node
113+
) => {
103114
if (
104115
node.type === 'NumericLiteral' ||
105116
node.type === 'StringLiteral'
106117
) {
107118
return node.value
108119
} else if (node.type === 'MemberExpression') {
109-
const exp = content.slice(node.start, node.end)
120+
const exp = content.slice(node.start ?? 0, node.end ?? 0)
110121
if (!(exp in enumData.defines)) {
111122
throw new Error(
112123
`unhandled enum initialization expression ${exp} in ${file}`
@@ -158,6 +169,10 @@ export function scanEnums() {
158169
}
159170
}
160171
}
172+
if (!(file in enumData.declarations)) {
173+
enumData.declarations[file] = []
174+
}
175+
enumData.declarations[file].push(declaration)
161176
}
162177
}
163178
}
@@ -174,71 +189,58 @@ export function scanEnums() {
174189
/**
175190
* @returns {[import('rollup').Plugin, Record<string, string>]}
176191
*/
177-
export function constEnum() {
192+
export function simplifyEnum() {
178193
if (!existsSync(ENUM_CACHE_PATH)) {
179194
throw new Error('enum cache needs to be initialized before creating plugin')
180195
}
181196
/**
182-
* @type {{ ranges: Record<string, [number, number][]>, defines: Record<string, string>, ids: string[] }}
197+
* @type {EnumData}
183198
*/
184199
const enumData = JSON.parse(readFileSync(ENUM_CACHE_PATH, 'utf-8'))
185200

186-
// construct a regex for matching re-exports of known const enums
187-
const reExportsRE = new RegExp(
188-
`export {[^}]*?\\b(${enumData.ids.join('|')})\\b[^]*?}`
189-
)
190-
191201
// 3. during transform:
192-
// 3.1 files w/ const enum declaration: remove declaration
193-
// 3.2 files using const enum: inject into esbuild define
202+
// 3.1 files w/ enum declaration: remove declaration
203+
// 3.2 files using enum: inject into esbuild define
194204
/**
195205
* @type {import('rollup').Plugin}
196206
*/
197207
const plugin = {
198-
name: 'remove-const-enum',
208+
name: 'simplify-enum',
199209
transform(code, id) {
200210
let s
201211

202-
if (id in enumData.ranges) {
212+
if (id in enumData.declarations) {
203213
s = s || new MagicString(code)
204-
for (const [start, end] of enumData.ranges[id]) {
205-
s.remove(start, end)
206-
}
207-
}
214+
for (const declaration of enumData.declarations[id]) {
215+
const {
216+
range: [start, end],
217+
id,
218+
members
219+
} = declaration
220+
s.update(
221+
start,
222+
end,
223+
`export const ${id} = {${members
224+
.flatMap(({ name, value }) => {
225+
const forwardMapping =
226+
JSON.stringify(name) + ': ' + JSON.stringify(value)
227+
const reverseMapping =
228+
JSON.stringify(value.toString()) + ': ' + JSON.stringify(name)
208229
209-
// check for const enum re-exports that must be removed
210-
if (reExportsRE.test(code)) {
211-
s = s || new MagicString(code)
212-
const ast = parse(code, {
213-
plugins: ['typescript'],
214-
sourceType: 'module'
215-
})
216-
for (const node of ast.program.body) {
217-
if (
218-
node.type === 'ExportNamedDeclaration' &&
219-
node.exportKind !== 'type' &&
220-
node.source
221-
) {
222-
for (let i = 0; i < node.specifiers.length; i++) {
223-
const spec = node.specifiers[i]
224-
if (
225-
spec.type === 'ExportSpecifier' &&
226-
spec.exportKind !== 'type' &&
227-
enumData.ids.includes(spec.local.name)
228-
) {
229-
const next = node.specifiers[i + 1]
230-
if (next) {
231-
// @ts-ignore
232-
s.remove(spec.start, next.start)
233-
} else {
234-
// last one
235-
const prev = node.specifiers[i - 1]
236-
// @ts-ignore
237-
s.remove(prev ? prev.end : spec.start, spec.end)
238-
}
239-
}
240-
}
241-
}
230+
// see https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings
231+
return typeof value === 'string'
232+
? [
233+
forwardMapping
234+
// string enum members do not get a reverse mapping generated at all
235+
]
236+
: [
237+
forwardMapping,
238+
// other enum members should support enum reverse mapping
239+
reverseMapping
240+
]
241+
})
242+
.join(',\n')}}`
243+
)
242244
}
243245
}
244246

0 commit comments

Comments
 (0)
Please sign in to comment.