UNPKG

directive-to-hof

Version:

Transform directives into a higher order function

183 lines 16.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createDirectiveTransformer = createDirectiveTransformer; const parser = __importStar(require("@babel/parser")); const traverse_1 = __importDefault(require("@babel/traverse")); const generator_1 = __importDefault(require("@babel/generator")); const t = __importStar(require("@babel/types")); // @ts-ignore const traverse = traverse_1.default.default || traverse_1.default; // @ts-ignore const generate = generator_1.default.default || generator_1.default; const generateRandomString = (length = 6) => { const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join(''); }; /** * Creates a transformer that looks for a specific directive in the code and rewrites it accordingly by * wrapping the function in a call to the imported higher-order function. * @param options The options for the transformer. * @returns A function that takes the source code and arguments and returns the transformed code. */ function createDirectiveTransformer(options) { if (!options) { throw new Error('Options are required'); } if (!options.directive) { throw new Error('Directive is required'); } if (!options.importPath) { throw new Error('Import path is required'); } if (!options.importName) { throw new Error('Import name is required'); } if (typeof options.directive !== 'string') { throw new Error('Directive must be a string'); } const IMPORT_PATH = options.importPath; const DIRECTIVE = options.directive; const IDENTIFIER = options.importName; const ASYNC_ONLY = options.asyncOnly ?? true; const transformer = async (source, args) => { const ast = parser.parse(source, { sourceType: 'module', plugins: ['typescript', 'jsx'], }); let state = { needsImport: false, hasExistingImport: false, cacheIdentifierName: IDENTIFIER, modifications: [], }; // First pass: check for naming collisions and collect modifications traverse(ast, { Program: { enter(path) { const binding = path.scope.getBinding(IDENTIFIER); if (binding) { state.cacheIdentifierName = `${IDENTIFIER}_${generateRandomString()}`; } }, }, ImportDeclaration(path) { if (path.node.source.value === IMPORT_PATH && path.node.specifiers.some((spec) => t.isImportSpecifier(spec) && // @ts-ignore spec.imported.name === IDENTIFIER)) { state.hasExistingImport = true; if (state.cacheIdentifierName !== IDENTIFIER) { // @ts-ignore state.modifications.push(() => { path.node.specifiers.forEach((spec) => { if (t.isImportSpecifier(spec) && // @ts-ignore spec.imported.name === IDENTIFIER) { spec.local.name = state.cacheIdentifierName; } }); }); } } }, 'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression|ObjectMethod'(path) { const body = t.isBlockStatement(path.node.body) ? path.node.body : null; const hasUseCache = body?.directives?.some((d) => d.value.value === DIRECTIVE); if (!hasUseCache && !t.isBlockStatement(path.node.body)) { const parentFunction = path.findParent((p) => (p.isFunction() || p.isProgram()) && 'directives' in p.node); if (!parentFunction?.node.directives?.some((d) => d.value.value === DIRECTIVE)) { return; } } if (hasUseCache || !t.isBlockStatement(path.node.body)) { // Check if the function is async if (ASYNC_ONLY && !path.node.async) { throw new Error(`"${DIRECTIVE}" directive may only be used in async functions at ${args.path}\n\n${path.toString()}\n^^^^${'-'.repeat(6)} This function must be async`); } state.needsImport = true; const isDeclaration = t.isFunctionDeclaration(path.node); const name = isDeclaration ? path.node.id?.name : undefined; // Create a new body without the 'use cache' directive const newBody = t.isBlockStatement(path.node.body) ? t.blockStatement(path.node.body.body, path.node.body.directives.filter((d) => d.value.value !== DIRECTIVE)) : path.node.body; const wrapped = t.callExpression(t.identifier(state.cacheIdentifierName), [ t.arrowFunctionExpression(path.node.params, newBody, path.node.async), ]); // @ts-ignore state.modifications.push(() => { if (t.isObjectMethod(path.node)) { path.replaceWith(t.objectProperty(t.identifier(path.node.key.name), wrapped)); } else if (name) { path.replaceWith(t.variableDeclaration('const', [ t.variableDeclarator(t.identifier(name), wrapped), ])); } else if (!t.isVariableDeclarator(path.parent)) { path.replaceWith(wrapped); } else { path.parent.init = wrapped; } }); } }, }); // Apply all collected modifications if (state.modifications.length > 0) { // Add import if needed if (state.needsImport && !state.hasExistingImport) { ast.program.body.unshift(t.importDeclaration([ t.importSpecifier(t.identifier(state.cacheIdentifierName), t.identifier(IDENTIFIER)), ], t.stringLiteral(IMPORT_PATH))); } // Apply collected modifications // @ts-ignore state.modifications.forEach((modify) => modify()); } const { code } = generate(ast); return { contents: code, loader: args.path?.split('.').pop(), }; }; return transformer; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNmb3JtZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHJhbnNmb3JtZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUEyQ0EsZ0VBZ01DO0FBM09ELHNEQUF3QztBQUN4QywrREFBd0M7QUFDeEMsaUVBQXlDO0FBQ3pDLGdEQUFrQztBQUVsQyxhQUFhO0FBQ2IsTUFBTSxRQUFRLEdBQUcsa0JBQVMsQ0FBQyxPQUFPLElBQUksa0JBQVMsQ0FBQztBQUNoRCxhQUFhO0FBQ2IsTUFBTSxRQUFRLEdBQUcsbUJBQVMsQ0FBQyxPQUFPLElBQUksbUJBQVMsQ0FBQztBQUVoRCxNQUFNLG9CQUFvQixHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxFQUFFO0lBQzFDLE1BQU0sS0FBSyxHQUFHLHNEQUFzRCxDQUFDO0lBQ3JFLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FDZixFQUFFLE1BQU0sRUFBRSxFQUNWLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FDdEQsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDYixDQUFDLENBQUM7QUFxQkY7Ozs7O0dBS0c7QUFDSCxTQUFnQiwwQkFBMEIsQ0FDeEMsT0FBb0M7SUFFcEMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUN4QixNQUFNLElB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