Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow Unicode extended escapes in ES5 and earlier (#50918)
* Remove language version check for extended escapes.

* Accepted baselines.

* Record whether nodes have extended Unicode escapes. Replace them in the es2015 transform.

* Accepted baselines.

* Move file to better-reflect generality of tests.

* Added tests for variables at the top level.

* Accepted baselines.

* Added test for extended astral character.

* Accepted baseline.

* Enable sourcemaps in tests.

* Accepted baselines.

* Call `setOriginalNode` on identifiers with extended escapes.
  • Loading branch information
DanielRosenwasser committed Sep 30, 2022
1 parent 58bae8d commit 0d0a793
Show file tree
Hide file tree
Showing 36 changed files with 7,010 additions and 497 deletions.
6 changes: 5 additions & 1 deletion src/compiler/factory/nodeFactory.ts
Expand Up @@ -874,7 +874,7 @@ namespace ts {
}

// @api
function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind): Identifier {
function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier {
const node = createBaseIdentifier(text, originalKeywordKind);
if (typeArguments) {
// NOTE: we do not use `setChildren` here because typeArguments in an identifier do not contribute to transformations
Expand All @@ -883,6 +883,10 @@ namespace ts {
if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) {
node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait;
}
if (hasExtendedUnicodeEscape) {
node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
node.transformFlags |= TransformFlags.ContainsES2015;
}
return node;
}

Expand Down
3 changes: 2 additions & 1 deletion src/compiler/parser.ts
Expand Up @@ -2187,8 +2187,9 @@ namespace ts {
// Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker
const originalKeywordKind = token();
const text = internIdentifier(scanner.getTokenValue());
const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape();
nextTokenWithoutCheck();
return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos);
return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos);
}

if (token() === SyntaxKind.PrivateIdentifier) {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scanner.ts
Expand Up @@ -1486,7 +1486,7 @@ namespace ts {


function peekExtendedUnicodeEscape(): number {
if (languageVersion >= ScriptTarget.ES2015 && codePointAt(text, pos + 1) === CharacterCodes.u && codePointAt(text, pos + 2) === CharacterCodes.openBrace) {
if (codePointAt(text, pos + 1) === CharacterCodes.u && codePointAt(text, pos + 2) === CharacterCodes.openBrace) {
const start = pos;
pos += 3;
const escapedValueString = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false);
Expand Down
13 changes: 9 additions & 4 deletions src/compiler/transformers/es2015.ts
Expand Up @@ -643,11 +643,16 @@ namespace ts {
}

function visitIdentifier(node: Identifier): Identifier {
if (!convertedLoopState) {
return node;
if (convertedLoopState) {
if (resolver.isArgumentsLocalBinding(node)) {
return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments"));
}
}
if (resolver.isArgumentsLocalBinding(node)) {
return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments"));
if (node.hasExtendedUnicodeEscape) {
return setOriginalNode(setTextRange(
factory.createIdentifier(unescapeLeadingUnderscores(node.escapedText)),
node
), node);
}
return node;
}
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/types.ts
Expand Up @@ -1427,6 +1427,7 @@ namespace ts {
isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace
/*@internal*/ typeArguments?: NodeArray<TypeNode | TypeParameterDeclaration>; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help.
/*@internal*/ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id.<T>
/*@internal*/ hasExtendedUnicodeEscape?: boolean;
}

// Transient identifier node (marked by id === -1)
Expand Down Expand Up @@ -7653,7 +7654,7 @@ namespace ts {
//

createIdentifier(text: string): Identifier;
/* @internal */ createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
/* @internal */ createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
/* @internal */ updateIdentifier(node: Identifier, typeArguments: NodeArray<TypeNode | TypeParameterDeclaration> | undefined): Identifier;

/**
Expand Down

0 comments on commit 0d0a793

Please sign in to comment.