import {NodePath} from '@babel/core';
import * as t from '@babel/types';
import {PluginOptions} from './Options';
export function insertGatedFunctionDeclaration(
fnPath: NodePath<
t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression
>,
compiled:
| t.FunctionDeclaration
| t.ArrowFunctionExpression
| t.FunctionExpression,
gating: NonNullable<PluginOptions['gating']>,
): void {
const gatingExpression = t.conditionalExpression(
t.callExpression(t.identifier(gating.importSpecifierName), []),
buildFunctionExpression(compiled),
buildFunctionExpression(fnPath.node),
);
if (
fnPath.parentPath.node.type !== 'ExportDefaultDeclaration' &&
fnPath.node.type === 'FunctionDeclaration' &&
fnPath.node.id != null
) {
fnPath.replaceWith(
t.variableDeclaration('const', [
t.variableDeclarator(fnPath.node.id, gatingExpression),
]),
);
} else if (
fnPath.parentPath.node.type === 'ExportDefaultDeclaration' &&
fnPath.node.type !== 'ArrowFunctionExpression' &&
fnPath.node.id != null
) {
fnPath.insertAfter(
t.exportDefaultDeclaration(t.identifier(fnPath.node.id.name)),
);
fnPath.parentPath.replaceWith(
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(fnPath.node.id.name),
gatingExpression,
),
]),
);
} else {
fnPath.replaceWith(gatingExpression);
}
}
function buildFunctionExpression(
node:
| t.FunctionDeclaration
| t.ArrowFunctionExpression
| t.FunctionExpression,
): t.ArrowFunctionExpression | t.FunctionExpression {
if (
node.type === 'ArrowFunctionExpression' ||
node.type === 'FunctionExpression'
) {
return node;
} else {
const fn: t.FunctionExpression = {
type: 'FunctionExpression',
async: node.async,
generator: node.generator,
loc: node.loc ?? null,
id: node.id ?? null,
params: node.params,
body: node.body,
};
return fn;
}
}