Skip to content

Commit

Permalink
Update Visit.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolaRHristov authored Nov 3, 2024
1 parent 933d37c commit f225b54
Showing 1 changed file with 140 additions and 123 deletions.
263 changes: 140 additions & 123 deletions Source/Function/Output/Transformer/Visit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,174 +4,191 @@ import type { Node } from "typescript";
/**
* @module Output
*/
export const Fn = ((Usage, Initializer) =>
(...[Context]) =>
(...[Node]) => {
export const Fn = ((Usage: Map<string, number>, Initializer: Map<string, Node>) =>
(Context: ts.TransformationContext) =>
(Node: Node): Node => {
const MAX_RECURSIVE_DEPTH = 100;
const MAX_NODE_VISITS = 100;
const MAX_ITERATIONS = 100;

const _Visit = (
Node: Node,
Depth = 0
): { Node: Node; Use: boolean } => {
if (++Visit >= MAX_NODE_VISITS || Depth >= MAX_RECURSIVE_DEPTH) {
return { Node, Use: false };
}

if (ts.isArrayLiteralExpression(Node)) {
const parent = Node.parent;
if (ts.isIdentifier(parent) || ts.isPropertyAccessExpression(parent)) {
return {
Node: factory.createIdentifier("array_expression"),
Use: true
};
}
}
let visit = 0;

if (ts.isEmptyStatement(Node)) {
const handlePropertyAccess = (node: Node, parent: Node): { Node: Node; Use: boolean } => {
if (ts.isPropertyAssignment(parent)) {
return {
Node: factory.createNotEmittedStatement(Node),
Node: factory.createIdentifier(
ts.isPropertyAccessExpression(node) ? node.name.text : ''
),
Use: true
};
}
return { Node: node, Use: false };
};

const handleIdentifier = (node: ts.Identifier): { Node: Node; Use: boolean } => {
try {
const nodeName = node.text;
const usage = Usage.get(nodeName);
const initializer = Get(nodeName, Initializer);

if (ts.isVariableStatement(Node)) {
const declarations = Node.declarationList.declarations.filter(declaration => {
if (isIdentifier(declaration.name)) {
const count = Usage.get(declaration.name.text);
return !count || count > 1 || !declaration.initializer;
if (!initializer || usage !== 1) {
return { Node: node, Use: false };
}

const parent = node.parent;
if (ts.isPropertyAccessExpression(parent)) {
if (parent.name.text === node.text) {
return { Node: node, Use: false };
}
return true;
});
}

if (declarations.length === 0) {
return {
Node: factory.createEmptyStatement(),
Use: true
};
if (ts.isPropertyAssignment(parent) &&
ts.isIdentifier(parent.name) &&
parent.name.text === node.text) {
return { Node: node, Use: false };
}

if (declarations.length !== Node.declarationList.declarations.length) {
return {
Node: factory.updateVariableStatement(
Node,
Node.modifiers,
factory.createVariableDeclarationList(
declarations,
Node.declarationList.flags
)
),
Use: true
if (isIdentifier(initializer)) {
if ((ts.isPropertyAccessExpression(parent) ||
ts.isPropertyAssignment(parent)) &&
parent.name === node) {
return { Node: node, Use: false };
}
return {
Node: factory.createIdentifier(initializer.text),
Use: true
};
}
}

if (isIdentifier(Node)) {
try {
const nodeName = Node.text;
const nodeUsage = Usage.get(nodeName);
const nodeInitializer = Get(nodeName, Initializer);
const transformed = ts.transform(initializer, [
(context) => (node) => node,
]).transformed[0];

if (nodeInitializer && nodeUsage === 1) {
const parent = Node.parent;
if (!transformed) {
return { Node: node, Use: false };
}

if (ts.isPropertyAccessExpression(parent) && parent.name.text === Node.text) {
return { Node, Use: false };
}
const newParent = transformed.parent;
if (ts.isPropertyAccessExpression(newParent) &&
ts.isIdentifier(newParent.name) &&
newParent.name.text === node.text) {
return { Node: node, Use: false };
}

if (ts.isPropertyAssignment(parent) &&
ts.isIdentifier(parent.name) &&
parent.name.text === Node.text) {
return { Node, Use: false };
}
return { Node: transformed as Node, Use: true };
} catch (error) {
console.error("Error during identifier replacement:", error);
return { Node: node, Use: false };
}
};

if (isIdentifier(nodeInitializer)) {
if ((ts.isPropertyAccessExpression(parent) || ts.isPropertyAssignment(parent)) &&
parent.name === Node) {
return { Node, Use: false };
}
return {
Node: factory.createIdentifier(nodeInitializer.text),
Use: true
};
}
const handleVariableStatement = (node: ts.VariableStatement): { Node: Node; Use: boolean } => {
const declarations = node.declarationList.declarations.filter(declaration => {
if (!isIdentifier(declaration.name)) return true;
const count = Usage.get(declaration.name.text);
return !count || count > 1 || !declaration.initializer;
});

const transformed = ts.transform(nodeInitializer, [
(_Context) => (node) => node
]).transformed[0];

if (transformed) {
const newParent = transformed.parent;
if (ts.isPropertyAccessExpression(newParent) &&
ts.isIdentifier(newParent.name) &&
newParent.name.text === Node.text) {
return { Node, Use: false };
}
return { Node: transformed as Node, Use: true };
}
}
} catch (error) {
console.error("Error during identifier replacement:", error);
}
if (declarations.length === 0) {
return {
Node: factory.createEmptyStatement(),
Use: true
};
}

if (declarations.length === node.declarationList.declarations.length) {
return { Node: node, Use: false };
}

return {
Node: factory.updateVariableStatement(
node,
node.modifiers,
factory.createVariableDeclarationList(
declarations,
node.declarationList.flags
)
),
Use: true
};
};

const _Visit = (
node: Node,
depth = 0
): { Node: Node; Use: boolean } => {
if (++visit >= MAX_NODE_VISITS || depth >= MAX_RECURSIVE_DEPTH) {
return { Node: node, Use: false };
}

if (ts.isPropertyAccessExpression(Node)) {
const parent = Node.parent;
if (ts.isPropertyAssignment(parent)) {
// Handle array literals
if (ts.isArrayLiteralExpression(node)) {
const parent = node.parent;
if (ts.isIdentifier(parent) || ts.isPropertyAccessExpression(parent)) {
return {
Node: factory.createIdentifier(Node.name.text),
Node: factory.createIdentifier("array_expression"),
Use: true
};
}
}

let childrenUse = false;
let shouldReturn = false;
// Handle empty statements
if (ts.isEmptyStatement(node)) {
return {
Node: factory.createNotEmittedStatement(node),
Use: true
};
}

const newNode = ts.visitEachChild(
Node,
(child) => {
if (shouldReturn) return child;
// Handle different node types
if (ts.isVariableStatement(node)) {
return handleVariableStatement(node);
}

const output = _Visit(child, Depth + 1);
if (output.Use === false && Depth > MAX_RECURSIVE_DEPTH) {
shouldReturn = true;
return child;
}
if (isIdentifier(node)) {
return handleIdentifier(node);
}

childrenUse = childrenUse || output.Use;
if (ts.isPropertyAccessExpression(node)) {
return handlePropertyAccess(node, node.parent);
}

// Handle child nodes
let use = false;
const newNode = ts.visitEachChild(
node,
(child) => {
const output = _Visit(child, depth + 1);
use = use || output.Use;
return output.Node;
},
Context
);

return {
Node: newNode,
Use: childrenUse
};
return { Node: newNode, Use: use };
};

// Main transformation loop
let currentNode = Node;
let use = true;
let iteration = 0;
let visit = 0;

while (use && iteration < MAX_ITERATIONS) {
if (iteration >= MAX_ITERATIONS) {
console.warn(
`Warning: Maximum iteration count (${MAX_ITERATIONS}) reached. Possible infinite loop detected.`,
{
TypeNode: ts.SyntaxKind[currentNode.kind],
Position: currentNode.pos,
Depth: "root"
}
);
break;
while (iteration < MAX_ITERATIONS) {
const output = _Visit(currentNode);

if (!output.Use || iteration >= MAX_ITERATIONS - 1) {
if (iteration >= MAX_ITERATIONS - 1) {
console.warn(
`Warning: Maximum iteration count (${MAX_ITERATIONS}) reached. Possible infinite loop detected.`,
{
TypeNode: ts.SyntaxKind[currentNode.kind],
Position: currentNode.pos,
Depth: "root"
}
);
}
return output.Node;
}

const output = _Visit(currentNode);
use = output.Use;
currentNode = output.Node;
iteration++;
}
Expand Down

0 comments on commit f225b54

Please sign in to comment.