Skip to content

Commit d6aa219

Browse files
authored
Merge pull request #2 from Fonger/feat/support-export-later
Feat/support export later
2 parents 8bd8d10 + aae0b06 commit d6aa219

File tree

5 files changed

+99
-46
lines changed

5 files changed

+99
-46
lines changed

README.md

-15
Original file line numberDiff line numberDiff line change
@@ -148,18 +148,3 @@ export default {
148148
],
149149
};
150150
```
151-
152-
# Caveats
153-
154-
Currently, only immediate export const enum works. For example:
155-
156-
```ts
157-
// The following works
158-
export const enum WorkingEnum {}
159-
160-
// The following doesn't work
161-
const enum FailingEnum {}
162-
export FailEnum;
163-
```
164-
165-
This may be fixed in future release.
+35-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`transform export const enum into object literal test-case/const-enum.d.ts 1`] = `
4-
"export declare enum SomeEnum {
4+
"declare enum SomeEnum {
55
A = 0,
66
B = 1,
77
C = \\"hello\\",
88
D = 1000,
99
E = 1001
1010
}
11-
export declare enum ComputedEnum {
11+
declare enum ComputedEnum {
1212
A = 0,
1313
B = 1,
1414
C = 2,
@@ -21,24 +21,36 @@ export declare enum ComputedEnum {
2121
J = \\"12\\",
2222
K = 1
2323
}
24+
export { ComputedEnum, SomeEnum };
25+
export declare enum DirectExportEnum {
26+
HI = \\"HELLO\\",
27+
WD = \\"WORLD\\"
28+
}
29+
declare enum DefaultExportConstEnum {
30+
X = 0
31+
}
32+
export default DefaultExportConstEnum;
33+
declare const enum NonExportConstEnum {
34+
A = 666,
35+
B = 888
36+
}
2437
declare enum NonExportEnum {
2538
A = 0,
2639
B = 1
2740
}
28-
declare function SomeFunc(inlineSomeEnum: SomeEnum, inlineComputedEnum: ComputedEnum): SomeEnum.D | ComputedEnum | NonExportEnum;
29-
export default SomeFunc;
41+
export declare function SomeFunc(inlineSomeEnum: SomeEnum, inlineComputedEnum: ComputedEnum): SomeEnum.D | ComputedEnum | NonExportConstEnum.A | NonExportEnum.B;
3042
"
3143
`;
3244

3345
exports[`transform export const enum into object literal test-case/const-enum.js 1`] = `
34-
"export const SomeEnum = {
46+
"const SomeEnum = {
3547
A: 0,
3648
B: 1,
3749
C: \\"hello\\",
3850
D: 1000,
3951
E: 1001
4052
};
41-
export const ComputedEnum = {
53+
const ComputedEnum = {
4254
A: 0,
4355
B: 1,
4456
C: 2,
@@ -51,21 +63,34 @@ export const ComputedEnum = {
5163
J: \\"12\\",
5264
K: 1
5365
};
66+
export { ComputedEnum, SomeEnum };
67+
export const DirectExportEnum = {
68+
HI: \\"HELLO\\",
69+
WD: \\"WORLD\\"
70+
};
71+
const DefaultExportConstEnum = {
72+
X: 0
73+
};
74+
export default DefaultExportConstEnum;
5475
const Value = 0.5;
76+
var NonExportConstEnum;
77+
(function (NonExportConstEnum) {
78+
NonExportConstEnum[NonExportConstEnum[\\"A\\"] = 666] = \\"A\\";
79+
NonExportConstEnum[NonExportConstEnum[\\"B\\"] = 888] = \\"B\\";
80+
})(NonExportConstEnum || (NonExportConstEnum = {}));
5581
var NonExportEnum;
5682
(function (NonExportEnum) {
5783
NonExportEnum[NonExportEnum[\\"A\\"] = 0] = \\"A\\";
5884
NonExportEnum[NonExportEnum[\\"B\\"] = 1] = \\"B\\";
5985
})(NonExportEnum || (NonExportEnum = {}));
60-
function SomeFunc(inlineSomeEnum, inlineComputedEnum) {
86+
export function SomeFunc(inlineSomeEnum, inlineComputedEnum) {
6187
if (inlineSomeEnum === 0 /* A */)
6288
return 1000 /* D */;
6389
if (inlineComputedEnum === -2 /* D */)
6490
return 4 /* E */;
65-
return Math.random() > Value ? NonExportEnum.A : NonExportEnum.B;
91+
return Math.random() > Value ? 666 /* A */ : NonExportEnum.B;
6692
}
67-
export default SomeFunc;
6893
//# sourceMappingURL=const-enum.js.map"
6994
`;
7095

71-
exports[`transform export const enum into object literal test-case/const-enum.js.map 1`] = `"{\\"version\\":3,\\"file\\":\\"const-enum.js\\",\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"const-enum.ts\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,MAAM,OAAY,QAAQ;IACxB,IAAC;IACD,IAAC;IACD,UAAW;IACX,OAAQ;IACR,OAAC;EACF;AAED,MAAM,OAAY,YAAY;IAC5B,IAAC;IACD,IAAC;IACD,IAAC;IACD,KAAU;IACV,IAAU;IACV,KAAc;IACd,OAAuB;IACvB,KAA4B;IAC5B,MAAgB;IAChB,OAAa;IACb,IAAoB;EACrB;AAED,MAAM,KAAK,GAAG,GAAG,CAAC;AAElB,IAAK,aAGJ;AAHD,WAAK,aAAa;IAChB,2CAAC,CAAA;IACD,2CAAC,CAAA;AACH,CAAC,EAHI,aAAa,KAAb,aAAa,QAGjB;AAED,SAAS,QAAQ,CAAC,cAAwB,EAAE,kBAAgC;IAC1E,IAAI,cAAc,cAAe;QAAE,oBAAkB;IACrD,IAAI,kBAAkB,eAAmB;QAAE,iBAAsB;IACjE,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,eAAe,QAAQ,CAAC\\"}"`;
96+
exports[`transform export const enum into object literal test-case/const-enum.js.map 1`] = `"{\\"version\\":3,\\"file\\":\\"const-enum.js\\",\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"const-enum.ts\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,MAAW,QAAQ;IACjB,IAAC;IACD,IAAC;IACD,UAAW;IACX,OAAQ;IACR,OAAC;EACF;AAED,MAAW,YAAY;IACrB,IAAC;IACD,IAAC;IACD,IAAC;IACD,KAAU;IACV,IAAU;IACV,KAAc;IACd,OAAuB;IACvB,KAA4B;IAC5B,MAAgB;IAChB,OAAa;IACb,IAAoB;EACrB;AACD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AAElC,MAAM,OAAY,gBAAgB;IAChC,WAAY;IACZ,WAAY;EACb;AAED,MAAW,sBAAsB;IAC/B,IAAC;EACF;AAED,eAAe,sBAAsB,CAAC;AAEtC,MAAM,KAAK,GAAG,GAAG,CAAC;AAElB,IAAW,kBAGV;AAHD,WAAW,kBAAkB;IAC3B,uDAAO,CAAA;IACP,uDAAO,CAAA;AACT,CAAC,EAHU,kBAAkB,KAAlB,kBAAkB,QAG5B;AAED,IAAK,aAGJ;AAHD,WAAK,aAAa;IAChB,2CAAC,CAAA;IACD,2CAAC,CAAA;AACH,CAAC,EAHI,aAAa,KAAb,aAAa,QAGjB;AAED,MAAM,UAAU,QAAQ,CAAC,cAAwB,EAAE,kBAAgC;IACjF,IAAI,cAAc,cAAe;QAAE,oBAAkB;IACrD,IAAI,kBAAkB,eAAmB;QAAE,iBAAsB;IACjE,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,aAAsB,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AACxE,CAAC\\"}"`;

src/transform.ts

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
import ts from 'typescript';
2-
import { evaluate, getModifier } from './utils';
2+
import { evaluate, getExportedNamesOfSource, hasModifier } from './utils';
33

44
export default function(program: ts.Program, pluginOptions?: unknown) {
55
return (ctx: ts.TransformationContext) => {
66
return (sourceFile: ts.SourceFile) => {
7-
const ambient = sourceFile.isDeclarationFile;
8-
97
return ts.visitEachChild(sourceFile, visitor, ctx);
10-
118
function visitor(node: ts.Node): ts.Node {
129
if (!ts.isEnumDeclaration(node)) {
1310
return ts.visitEachChild(node, visitor, ctx);
1411
}
15-
const exportModifier = getModifier(node, ts.SyntaxKind.ExportKeyword);
16-
if (!exportModifier) return node;
17-
const constModifier = getModifier(node, ts.SyntaxKind.ConstKeyword);
18-
if (!constModifier) return node;
1912

20-
if (ambient) {
13+
if (!hasModifier(node, ts.SyntaxKind.ConstKeyword)) {
14+
return node;
15+
}
16+
17+
if (!hasModifier(node, ts.SyntaxKind.ExportKeyword)) {
18+
const exportedNames = getExportedNamesOfSource(program, sourceFile);
19+
20+
if (!exportedNames.includes(node.name.text)) {
21+
return node;
22+
}
23+
}
24+
25+
if (sourceFile.isDeclarationFile) {
2126
return ts.visitEachChild(node, stripConstKeyword, ctx);
2227
}
2328

24-
return transformEnum(node, [exportModifier, constModifier]);
29+
return transformEnum(node);
2530
}
2631
};
2732
};
@@ -30,7 +35,7 @@ export default function(program: ts.Program, pluginOptions?: unknown) {
3035
return node.kind === ts.SyntaxKind.ConstKeyword ? undefined : node;
3136
}
3237

33-
function transformEnum(node: ts.EnumDeclaration, modifiers: ts.Modifier[]) {
38+
function transformEnum(node: ts.EnumDeclaration) {
3439
const members = node.members;
3540
const known = new Map<string, number | string>();
3641
const properties: ts.PropertyAssignment[] = [];
@@ -78,7 +83,7 @@ export default function(program: ts.Program, pluginOptions?: unknown) {
7883
}
7984

8085
const result = ts.factory.createVariableStatement(
81-
modifiers,
86+
node.modifiers,
8287
ts.factory.createVariableDeclarationList(
8388
[
8489
ts.factory.createVariableDeclaration(

src/utils.ts

+26-3
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,32 @@ export function evaluate(
7070
throw new Error('unexpected evaluation for enum member: ' + expr.getText);
7171
}
7272

73-
export function getModifier(node: ts.Node, modifier: ts.SyntaxKind) {
73+
export function hasModifier(node: ts.Node, modifier: ts.SyntaxKind) {
7474
return (
75-
node.modifiers
76-
&& node.modifiers.find((mod: ts.Modifier) => mod.kind === modifier)
75+
node.modifiers?.some((mod: ts.Modifier) => mod.kind === modifier)
7776
);
7877
}
78+
79+
const cachedNames = new WeakMap<ts.SourceFile, string[]>();
80+
export function getExportedNamesOfSource(program: ts.Program, sourceFile: ts.SourceFile) {
81+
const cached = cachedNames.get(sourceFile);
82+
if (cached) return cached;
83+
84+
const typeChecker = program.getTypeChecker();
85+
const sourceSymbol = typeChecker.getSymbolAtLocation(sourceFile);
86+
let names: string[];
87+
88+
if (sourceSymbol) {
89+
names = typeChecker.getExportsOfModule(sourceSymbol).map(s => {
90+
if (s.flags & ts.SymbolFlags.Alias) {
91+
return typeChecker.getAliasedSymbol(s).name;
92+
}
93+
return s.name;
94+
});
95+
} else {
96+
names = [];
97+
}
98+
99+
cachedNames.set(sourceFile, names);
100+
return names;
101+
}

test-case/const-enum.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
export const enum SomeEnum {
1+
const enum SomeEnum {
22
A,
33
B,
44
C = 'hello',
55
D = 1000,
66
E,
77
}
88

9-
export const enum ComputedEnum {
9+
const enum ComputedEnum {
1010
A,
1111
B,
1212
C,
@@ -19,18 +19,33 @@ export const enum ComputedEnum {
1919
J = '1' + '2',
2020
K = B & 1000 + H / 2,
2121
}
22+
export { ComputedEnum, SomeEnum };
23+
24+
export const enum DirectExportEnum {
25+
HI = 'HELLO',
26+
WD = 'WORLD',
27+
}
28+
29+
const enum DefaultExportConstEnum {
30+
X,
31+
}
32+
33+
export default DefaultExportConstEnum;
2234

2335
const Value = 0.5;
2436

37+
const enum NonExportConstEnum {
38+
A = 666,
39+
B = 888,
40+
}
41+
2542
enum NonExportEnum {
2643
A,
2744
B,
2845
}
2946

30-
function SomeFunc(inlineSomeEnum: SomeEnum, inlineComputedEnum: ComputedEnum) {
47+
export function SomeFunc(inlineSomeEnum: SomeEnum, inlineComputedEnum: ComputedEnum) {
3148
if (inlineSomeEnum === SomeEnum.A) return SomeEnum.D;
3249
if (inlineComputedEnum === ComputedEnum.D) return ComputedEnum.E;
33-
return Math.random() > Value ? NonExportEnum.A : NonExportEnum.B;
50+
return Math.random() > Value ? NonExportConstEnum.A : NonExportEnum.B;
3451
}
35-
36-
export default SomeFunc;

0 commit comments

Comments
 (0)