"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTempVarsDeclaration = exports.createHtmlProcessorWrapper = exports.createExpandedConcatOperation = exports.createArrayWrapper = exports.createGetPostMessageMethodCall = exports.createGetProxyUrlMethodCall = exports.getProxyUrlLiteral = exports.createGetEvalMethodCall = exports.createComputedPropertySetWrapper = exports.createComputedPropertyGetWrapper = exports.createPropertyGetWrapper = exports.createMethodCallWrapper = exports.createPropertySetWrapper = exports.createLocationSetWrapper = exports.createLocationGetWrapper = exports.createProcessScriptMethodCall = exports.createVariableDeclaration = exports.createVariableDeclarator = exports.createBlockStatement = exports.createAssignmentExprStmt = exports.createSimpleLiteral = exports.createConditionalExpression = exports.createUndefined = exports.createReturnStatement = exports.createSequenceExpression = exports.createBinaryExpression = exports.createMemberExpression = exports.createArrayExpression = exports.createSimpleCallExpression = exports.createAssignmentExpression = exports.createExpressionStatement = exports.createIdentifier = void 0;
const esotope_hammerhead_1 = require("esotope-hammerhead");
const instruction_1 = __importDefault(require("./instruction"));
const url_1 = require("../../utils/url");
const temp_variables_1 = __importDefault(require("./transformers/temp-variables"));
function createIdentifier(name) {
    return { type: esotope_hammerhead_1.Syntax.Identifier, name };
}
exports.createIdentifier = createIdentifier;
function createExpressionStatement(expression) {
    return { type: esotope_hammerhead_1.Syntax.ExpressionStatement, expression };
}
exports.createExpressionStatement = createExpressionStatement;
function createAssignmentExpression(left, operator, right) {
    //@ts-ignore the `right` value can actually be null, but the AssignmentExpression type definition
    // does not allow to the `right` value be null
    return { type: esotope_hammerhead_1.Syntax.AssignmentExpression, operator, left, right };
}
exports.createAssignmentExpression = createAssignmentExpression;
function createSimpleCallExpression(callee, args) {
    return { type: esotope_hammerhead_1.Syntax.CallExpression, callee, arguments: args, optional: false };
}
exports.createSimpleCallExpression = createSimpleCallExpression;
function createArrayExpression(elements) {
    return { type: esotope_hammerhead_1.Syntax.ArrayExpression, elements };
}
exports.createArrayExpression = createArrayExpression;
function createMemberExpression(object, property, computed) {
    return { type: esotope_hammerhead_1.Syntax.MemberExpression, object, property, computed, optional: false };
}
exports.createMemberExpression = createMemberExpression;
function createBinaryExpression(left, operator, right) {
    return { type: esotope_hammerhead_1.Syntax.BinaryExpression, left, right, operator };
}
exports.createBinaryExpression = createBinaryExpression;
function createSequenceExpression(expressions) {
    //@ts-ignore SequenceExpression can actually
    // TODO: To write to https://github.com/estree/estree that SequenceExpression must include Pattern
    return { type: esotope_hammerhead_1.Syntax.SequenceExpression, expressions };
}
exports.createSequenceExpression = createSequenceExpression;
function createThisExpression() {
    return { type: esotope_hammerhead_1.Syntax.ThisExpression };
}
function createLogicalExpression(left, operator, right) {
    return { type: esotope_hammerhead_1.Syntax.LogicalExpression, left, right, operator };
}
function createReturnStatement(argument = null) {
    return { type: esotope_hammerhead_1.Syntax.ReturnStatement, argument };
}
exports.createReturnStatement = createReturnStatement;
function createFunctionExpression(id, params, body, async = false, generator = false) {
    return { type: esotope_hammerhead_1.Syntax.FunctionExpression, id, params, body, async, generator };
}
function createUnaryExpression(operator, argument) {
    return { type: esotope_hammerhead_1.Syntax.UnaryExpression, operator, prefix: true, argument };
}
function createUndefined() {
    return createUnaryExpression('void', createSimpleLiteral(0));
}
exports.createUndefined = createUndefined;
function createConditionalExpression(test, consequent, alternate) {
    return { type: esotope_hammerhead_1.Syntax.ConditionalExpression, test, consequent, alternate };
}
exports.createConditionalExpression = createConditionalExpression;
function createSimpleLiteral(value) {
    return { type: esotope_hammerhead_1.Syntax.Literal, value };
}
exports.createSimpleLiteral = createSimpleLiteral;
function createAssignmentExprStmt(left, right) {
    return createExpressionStatement(createAssignmentExpression(left, '=', right));
}
exports.createAssignmentExprStmt = createAssignmentExprStmt;
function createBlockStatement(body) {
    return { type: esotope_hammerhead_1.Syntax.BlockStatement, body };
}
exports.createBlockStatement = createBlockStatement;
function createVariableDeclarator(id, init = null) {
    return { type: esotope_hammerhead_1.Syntax.VariableDeclarator, id, init };
}
exports.createVariableDeclarator = createVariableDeclarator;
function createVariableDeclaration(kind, declarations) {
    return { type: esotope_hammerhead_1.Syntax.VariableDeclaration, declarations, kind };
}
exports.createVariableDeclaration = createVariableDeclaration;
function createProcessScriptMethodCall(arg, isApply) {
    const args = [arg];
    const processScriptIdentifier = createIdentifier(instruction_1.default.processScript);
    if (isApply)
        args.push(createSimpleLiteral(true));
    return createSimpleCallExpression(processScriptIdentifier, args);
}
exports.createProcessScriptMethodCall = createProcessScriptMethodCall;
function createLocationGetWrapper(location) {
    const getLocationIdentifier = createIdentifier(instruction_1.default.getLocation);
    return createSimpleCallExpression(getLocationIdentifier, [location]);
}
exports.createLocationGetWrapper = createLocationGetWrapper;
function createLocationSetWrapper(locationIdentifier, value, wrapWithSequence) {
    const tempIdentifier = createIdentifier(temp_variables_1.default.generateName());
    const setLocationIdentifier = createIdentifier(instruction_1.default.setLocation);
    const setLocationCall = createSimpleCallExpression(setLocationIdentifier, [locationIdentifier, tempIdentifier]);
    const locationAssignment = createAssignmentExpression(locationIdentifier, '=', tempIdentifier);
    const callIdentifier = createIdentifier('call');
    const functionWrapper = createFunctionExpression(null, [], createBlockStatement([
        createVariableDeclaration('var', [createVariableDeclarator(tempIdentifier, value)]),
        createReturnStatement(createLogicalExpression(setLocationCall, '||', locationAssignment)),
    ]));
    const functionWrapperCallMember = createMemberExpression(functionWrapper, callIdentifier, false);
    const functionWrapperCall = createSimpleCallExpression(functionWrapperCallMember, [createThisExpression()]);
    if (wrapWithSequence)
        return createSequenceExpression([createSimpleLiteral(0), functionWrapperCall]);
    return functionWrapperCall;
}
exports.createLocationSetWrapper = createLocationSetWrapper;
function createPropertySetWrapper(propertyName, obj, value) {
    const setPropertyIdentifier = createIdentifier(instruction_1.default.setProperty);
    return createSimpleCallExpression(setPropertyIdentifier, [obj, createSimpleLiteral(propertyName), value]);
}
exports.createPropertySetWrapper = createPropertySetWrapper;
function createMethodCallWrapper(owner, method, methodArgs, optional = false) {
    const callMethodIdentifier = createIdentifier(instruction_1.default.callMethod);
    const methodArgsArray = createArrayExpression(methodArgs);
    const args = [owner, method, methodArgsArray];
    if (optional)
        args.push(createSimpleLiteral(optional));
    return createSimpleCallExpression(callMethodIdentifier, args);
}
exports.createMethodCallWrapper = createMethodCallWrapper;
function createPropertyGetWrapper(propertyName, owner, optional = false) {
    const getPropertyIdentifier = createIdentifier(instruction_1.default.getProperty);
    const args = [owner, createSimpleLiteral(propertyName)];
    if (optional)
        args.push(createSimpleLiteral(optional));
    return createSimpleCallExpression(getPropertyIdentifier, args);
}
exports.createPropertyGetWrapper = createPropertyGetWrapper;
function createComputedPropertyGetWrapper(property, owner, optional = false) {
    const getPropertyIdentifier = createIdentifier(instruction_1.default.getProperty);
    const args = [owner, property];
    if (optional)
        args.push(createSimpleLiteral(optional));
    return createSimpleCallExpression(getPropertyIdentifier, args);
}
exports.createComputedPropertyGetWrapper = createComputedPropertyGetWrapper;
function createComputedPropertySetWrapper(property, owner, value) {
    const setPropertyIdentifier = createIdentifier(instruction_1.default.setProperty);
    return createSimpleCallExpression(setPropertyIdentifier, [owner, property, value]);
}
exports.createComputedPropertySetWrapper = createComputedPropertySetWrapper;
function createGetEvalMethodCall(node) {
    const getEvalIdentifier = createIdentifier(instruction_1.default.getEval);
    return createSimpleCallExpression(getEvalIdentifier, [node]);
}
exports.createGetEvalMethodCall = createGetEvalMethodCall;
function getProxyUrlLiteral(source, resolver) {
    const proxyUrl = resolver(String(source.value), (0, url_1.getResourceTypeString)({ isScript: true }));
    return createSimpleLiteral(proxyUrl);
}
exports.getProxyUrlLiteral = getProxyUrlLiteral;
function createGetProxyUrlMethodCall(arg, baseUrl) {
    const getProxyUrlIdentifier = createIdentifier(instruction_1.default.getProxyUrl);
    const args = [arg];
    if (baseUrl)
        args.push(createSimpleLiteral(baseUrl));
    return createSimpleCallExpression(getProxyUrlIdentifier, args);
}
exports.createGetProxyUrlMethodCall = createGetProxyUrlMethodCall;
function createGetPostMessageMethodCall(node) {
    const getPostMessageIdentifier = createIdentifier(instruction_1.default.getPostMessage);
    const args = node.type === esotope_hammerhead_1.Syntax.MemberExpression
        ? [node.object]
        : [createSimpleLiteral(null), node];
    return createSimpleCallExpression(getPostMessageIdentifier, args);
}
exports.createGetPostMessageMethodCall = createGetPostMessageMethodCall;
function createArrayWrapper(array) {
    const arrayIdentifier = createIdentifier(instruction_1.default.arrayFrom);
    return createSimpleCallExpression(arrayIdentifier, [array]);
}
exports.createArrayWrapper = createArrayWrapper;
function createExpandedConcatOperation(left, right) {
    return createAssignmentExpression(left, '=', createBinaryExpression(left, '+', right));
}
exports.createExpandedConcatOperation = createExpandedConcatOperation;
function createHtmlProcessorWrapper(node) {
    const processHtmlIdentifier = createIdentifier(instruction_1.default.processHtml);
    const parentIdentifier = createIdentifier('parent');
    const windowIdentifier = createIdentifier('window');
    const processHtmlThroughParent = createMemberExpression(parentIdentifier, processHtmlIdentifier, false);
    const processHtmlCall = createSimpleCallExpression(processHtmlThroughParent, [windowIdentifier, node.expression]);
    return createExpressionStatement(processHtmlCall);
}
exports.createHtmlProcessorWrapper = createHtmlProcessorWrapper;
function createTempVarsDeclaration(tempVars) {
    const declarations = [];
    for (const variable of tempVars)
        declarations.push(createVariableDeclarator(createIdentifier(variable)));
    return createVariableDeclaration('var', declarations);
}
exports.createTempVarsDeclaration = createTempVarsDeclaration;