Fix identifiers generation (#1378)

This commit is contained in:
Timofey Kachalov
2026-01-28 01:04:40 +04:00
committed by GitHub
parent 999e93c084
commit 6864328c03
6 changed files with 126 additions and 46 deletions
@@ -58,8 +58,10 @@ export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomN
* @returns {TStatement[]}
*/
protected getNodeStructure(): TStatement[] {
// Use generateForGlobalScopeWithAllScopesValidation when in global scope
// to avoid shadowing variables in inner lexical scopes
const variableDeclarationName: string = NodeGuards.isProgramNode(this.lexicalScopeNode)
? this.identifierNamesGenerator.generateForGlobalScope()
? this.identifierNamesGenerator.generateForGlobalScopeWithAllScopesValidation()
: this.identifierNamesGenerator.generateForLexicalScope(this.lexicalScopeNode);
const structure: TStatement = NodeFactory.variableDeclarationNode(
@@ -150,6 +150,12 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
*/
public abstract generateForGlobalScope(nameLength?: number): string;
/**
* @param {number} nameLength
* @returns {string}
*/
public abstract generateForGlobalScopeWithAllScopesValidation(nameLength?: number): string;
/**
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {number} nameLength
@@ -81,18 +81,14 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
* @returns {string}
*/
public generateForGlobalScope(): string {
const prefix: string = this.options.identifiersPrefix ? `${this.options.identifiersPrefix}` : '';
return this.generateForGlobalScopeInternal((name) => this.isValidIdentifierName(name));
}
const identifierName: string = this.generateNewDictionaryName((newIdentifierName: string) => {
const identifierNameWithPrefix: string = `${prefix}${newIdentifierName}`;
return this.isValidIdentifierNameInAllScopes(identifierNameWithPrefix);
});
const identifierNameWithPrefix = `${prefix}${identifierName}`;
this.preserveName(identifierNameWithPrefix);
return identifierNameWithPrefix;
/**
* @returns {string}
*/
public generateForGlobalScopeWithAllScopesValidation(): string {
return this.generateForGlobalScopeInternal((name) => this.isValidIdentifierNameInAllScopes(name));
}
/**
@@ -121,6 +117,25 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
return this.generateNewDictionaryName();
}
/**
* @param {(name: string) => boolean} validationFn
* @returns {string}
*/
private generateForGlobalScopeInternal(validationFn: (name: string) => boolean): string {
const prefix: string = this.options.identifiersPrefix ? `${this.options.identifiersPrefix}` : '';
const identifierName: string = this.generateNewDictionaryName((newIdentifierName: string) => {
const identifierNameWithPrefix: string = `${prefix}${newIdentifierName}`;
return validationFn(identifierNameWithPrefix);
});
const identifierNameWithPrefix = `${prefix}${identifierName}`;
this.preserveName(identifierNameWithPrefix);
return identifierNameWithPrefix;
}
/**
* @param {(newIdentifierName: string) => boolean} validationFunction
* @returns {string}
@@ -33,23 +33,7 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
* @returns {string}
*/
public generateNext(nameLength?: number): string {
const rangeMinInteger: number = 10000;
const rangeMaxInteger: number = 99_999_999;
const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);
const hexadecimalNumber: string = NumberUtils.toHex(randomInteger);
const prefixLength: number = Utils.hexadecimalPrefix.length;
const baseNameLength: number =
(nameLength ?? HexadecimalIdentifierNamesGenerator.baseIdentifierNameLength) + prefixLength;
const baseIdentifierName: string = hexadecimalNumber.slice(0, baseNameLength);
const identifierName: string = `_${baseIdentifierName}`;
if (!this.isValidIdentifierNameInAllScopes(identifierName)) {
return this.generateNext(nameLength);
}
this.preserveName(identifierName);
return identifierName;
return this.generateNextName(nameLength, (name) => this.isValidIdentifierName(name));
}
/**
@@ -57,9 +41,15 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
* @returns {string}
*/
public generateForGlobalScope(nameLength?: number): string {
const identifierName: string = this.generateNext(nameLength);
return this.generateForGlobalScopeInternal(nameLength, (name) => this.isValidIdentifierName(name));
}
return `${this.options.identifiersPrefix}${identifierName}`.replace('__', '_');
/**
* @param {number} nameLength
* @returns {string}
*/
public generateForGlobalScopeWithAllScopesValidation(nameLength?: number): string {
return this.generateForGlobalScopeInternal(nameLength, (name) => this.isValidIdentifierNameInAllScopes(name));
}
/**
@@ -79,4 +69,43 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
public generateForLabel(label: string, nameLength?: number): string {
return this.generateNext(nameLength);
}
/**
* @param {number} nameLength
* @param {(name: string) => boolean} validationFn
* @returns {string}
*/
private generateForGlobalScopeInternal(
nameLength: number | undefined,
validationFn: (name: string) => boolean
): string {
const identifierName: string = this.generateNextName(nameLength, validationFn);
return `${this.options.identifiersPrefix}${identifierName}`.replace('__', '_');
}
/**
* @param {number} nameLength
* @param {(name: string) => boolean} validationFn
* @returns {string}
*/
private generateNextName(nameLength: number | undefined, validationFn: (name: string) => boolean): string {
const rangeMinInteger: number = 10000;
const rangeMaxInteger: number = 99_999_999;
const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);
const hexadecimalNumber: string = NumberUtils.toHex(randomInteger);
const prefixLength: number = Utils.hexadecimalPrefix.length;
const baseNameLength: number =
(nameLength ?? HexadecimalIdentifierNamesGenerator.baseIdentifierNameLength) + prefixLength;
const baseIdentifierName: string = hexadecimalNumber.slice(0, baseNameLength);
const identifierName: string = `_${baseIdentifierName}`;
if (!validationFn(identifierName)) {
return this.generateNextName(nameLength, validationFn);
}
this.preserveName(identifierName);
return identifierName;
}
}
@@ -96,22 +96,15 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
* @returns {string}
*/
public generateForGlobalScope(nameLength?: number): string {
const prefix: string = this.options.identifiersPrefix ? `${this.options.identifiersPrefix}` : '';
return this.generateForGlobalScopeInternal((name) => this.isValidIdentifierName(name));
}
const identifierName: string = this.generateNewMangledName(
this.lastMangledName,
(newIdentifierName: string) => {
const identifierNameWithPrefix: string = `${prefix}${newIdentifierName}`;
return this.isValidIdentifierNameInAllScopes(identifierNameWithPrefix);
}
);
const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
this.updatePreviousMangledName(identifierName);
this.preserveName(identifierNameWithPrefix);
return identifierNameWithPrefix;
/**
* @param {number} nameLength
* @returns {string}
*/
public generateForGlobalScopeWithAllScopesValidation(nameLength?: number): string {
return this.generateForGlobalScopeInternal((name) => this.isValidIdentifierNameInAllScopes(name));
}
/**
@@ -299,6 +292,29 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
return identifierName;
}
/**
* @param {(name: string) => boolean} validationFn
* @returns {string}
*/
private generateForGlobalScopeInternal(validationFn: (name: string) => boolean): string {
const prefix: string = this.options.identifiersPrefix ? `${this.options.identifiersPrefix}` : '';
const identifierName: string = this.generateNewMangledName(
this.lastMangledName,
(newIdentifierName: string) => {
const identifierNameWithPrefix: string = `${prefix}${newIdentifierName}`;
return validationFn(identifierNameWithPrefix);
}
);
const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
this.updatePreviousMangledName(identifierName);
this.preserveName(identifierNameWithPrefix);
return identifierNameWithPrefix;
}
/**
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
* @returns {string}
@@ -47,6 +47,18 @@ export interface IIdentifierNamesGenerator {
*/
isValidIdentifierNameInLexicalScopes(identifierName: string, lexicalScopeNodes: TNodeWithLexicalScope[]): boolean;
/**
* @param {string} identifierName
* @returns {boolean}
*/
isValidIdentifierNameInAllScopes(identifierName: string): boolean;
/**
* @param {number} nameLength
* @returns {string}
*/
generateForGlobalScopeWithAllScopesValidation(nameLength?: number): string;
/**
* @param {string} identifierName
*/