Skip to content

Commit f7e231f

Browse files
authored
Allow negative number in ambient const initializer (#15338)
* allow negative number in ambient const initializer * disallow parenthesized numbers
1 parent 77d1aa0 commit f7e231f

5 files changed

Lines changed: 731 additions & 13 deletions

File tree

packages/babel-parser/src/plugins/typescript/index.ts

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,24 +2778,12 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
27782778
if (!init) continue;
27792779

27802780
// var and let aren't ever allowed initializers.
2781-
//
2782-
// If a const declaration has no type annotation and is initiailized to
2783-
// a string literal, numeric literal, or enum reference, then it is
2784-
// allowed. In an ideal world, we'd check whether init was *actually* an
2785-
// enum reference, but we allow anything that "could be" a literal enum
2786-
// in `isPossiblyLiteralEnum` since we don't have all the information
2787-
// that the typescript compiler has.
27882781
if (kind !== "const" || !!id.typeAnnotation) {
27892782
this.raise(TSErrors.InitializerNotAllowedInAmbientContext, {
27902783
at: init,
27912784
});
27922785
} else if (
2793-
init.type !== "StringLiteral" &&
2794-
init.type !== "BooleanLiteral" &&
2795-
init.type !== "NumericLiteral" &&
2796-
init.type !== "BigIntLiteral" &&
2797-
(init.type !== "TemplateLiteral" || init.expressions.length > 0) &&
2798-
!isPossiblyLiteralEnum(init)
2786+
!isValidAmbientConstInitializer(init, this.hasPlugin("estree"))
27992787
) {
28002788
this.raise(
28012789
TSErrors.ConstInitiailizerMustBeStringOrNumericLiteralOrLiteralEnumReference,
@@ -4112,6 +4100,68 @@ function isPossiblyLiteralEnum(expression: N.Expression): boolean {
41124100
return isUncomputedMemberExpressionChain(expression.object);
41134101
}
41144102

4103+
// If a const declaration has no type annotation and is initiailized to
4104+
// a string literal, numeric literal, or enum reference, then it is
4105+
// allowed. In an ideal world, we'd check whether init was *actually* an
4106+
// enum reference, but we allow anything that "could be" a literal enum
4107+
// in `isPossiblyLiteralEnum` since we don't have all the information
4108+
// that the typescript compiler has.
4109+
function isValidAmbientConstInitializer(
4110+
expression: N.Expression,
4111+
estree: boolean,
4112+
): boolean {
4113+
const { type } = expression;
4114+
if (expression.extra?.parenthesized) {
4115+
return false;
4116+
}
4117+
if (estree) {
4118+
if (type === "Literal") {
4119+
const { value } = expression;
4120+
if (typeof value === "string" || typeof value === "boolean") {
4121+
return true;
4122+
}
4123+
}
4124+
} else {
4125+
if (type === "StringLiteral" || type === "BooleanLiteral") {
4126+
return true;
4127+
}
4128+
}
4129+
if (isNumber(expression, estree) || isNegativeNumber(expression, estree)) {
4130+
return true;
4131+
}
4132+
if (type === "TemplateLiteral" && expression.expressions.length === 0) {
4133+
return true;
4134+
}
4135+
if (isPossiblyLiteralEnum(expression)) {
4136+
return true;
4137+
}
4138+
return false;
4139+
}
4140+
4141+
function isNumber(expression: N.Expression, estree: boolean): boolean {
4142+
if (estree) {
4143+
return (
4144+
expression.type === "Literal" &&
4145+
(typeof expression.value === "number" || "bigint" in expression)
4146+
);
4147+
} else {
4148+
return (
4149+
expression.type === "NumericLiteral" ||
4150+
expression.type === "BigIntLiteral"
4151+
);
4152+
}
4153+
}
4154+
4155+
function isNegativeNumber(expression: N.Expression, estree: boolean): boolean {
4156+
if (expression.type === "UnaryExpression") {
4157+
const { operator, argument } = expression as N.UnaryExpression;
4158+
if (operator === "-" && isNumber(argument, estree)) {
4159+
return true;
4160+
}
4161+
}
4162+
return false;
4163+
}
4164+
41154165
function isUncomputedMemberExpressionChain(expression: N.Expression): boolean {
41164166
if (expression.type === "Identifier") return true;
41174167
if (expression.type !== "MemberExpression") return false;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
declare module N {
2+
enum E {
3+
ok = 0
4+
}
5+
6+
export const string = "2";
7+
export const number = 1.;
8+
export const bigint = 0n;
9+
export const negative_bigint = -0n;
10+
export const negative_number = -1;
11+
export const template = `-2`;
12+
export const False = false;
13+
export const True = true;
14+
export const E_ok = E.ok;
15+
}

0 commit comments

Comments
 (0)