All files / src/functions add.fastify.routes.ts

100% Statements 44/44
100% Branches 11/11
100% Functions 11/11
100% Lines 37/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83    2x 2x 2x             2x 2x       2x   2x       11x 11x   11x 11x   15x               15x 15x     11x 11x 14x 14x     11x 10x 10x   10x   10x 10x   10x 10x   10x 2x 4x     8x         11x 10x 10x       11x 1x 1x         2x  
'use strict';
 
import * as fs from 'node:fs';
import * as path from 'node:path';
import {hrtime} from 'node:process';
import {IncomingMessage, Server, ServerResponse} from 'node:http';
 
import {FastifyInstance} from 'fastify';
 
import type {ItemStat} from '@owservable/folders';
 
import addRoute from './add.route';
import cleanRelativePath from './clean.relative.path';
 
let routesRootFolder: string;
 
const NS_PER_SEC: number = 1e9;
 
const addFastifyRoutes = async (
	fastify: FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>>,
	folder: string,
	verbose: boolean = false
): Promise<void> => {
	if (!routesRootFolder) routesRootFolder = folder;
 
	const fileNames: string[] = await fs.promises.readdir(folder);
	const stats: ItemStat[] = await Promise.all(
		fileNames.map(
			async (name): Promise<ItemStat> => ({
				name,
				fullPath: path.join(folder, name),
				isDirectory: (await fs.promises.lstat(path.join(folder, name))).isDirectory()
			})
		)
	);
 
	const files: ItemStat[] = stats.filter((stat: ItemStat): boolean => !stat.isDirectory);
	const folders: ItemStat[] = stats.filter((stat: ItemStat): boolean => stat.isDirectory);
 
	// Process files in parallel batches for better performance
	const BATCH_SIZE = 10; // Process up to 10 files concurrently
	const validFiles: ItemStat[] = files.filter((file: ItemStat): boolean => {
		const ext: string = path.extname(file.name);
		return ext === '.ts' || ext === '.js';
	});
 
	const processFile = async (file: ItemStat): Promise<void> => {
		const ext: string = path.extname(file.name);
		const relativeFilePath: string = cleanRelativePath(routesRootFolder, file.fullPath, ext as '.ts' | '.js');
 
		const start: number = Number(hrtime.bigint());
 
		const routeModule: {default?: unknown} = require(file.fullPath) as {default?: unknown};
		const routes: unknown = routeModule.default || routeModule;
 
		const time: number = Number(Number(hrtime.bigint()) - start) / NS_PER_SEC;
		if (verbose) console.log('[@owservable/fastify-auto-routes] -> addFastifyRoutes: loaded file', `[${time.toFixed(3)}s] ${folder}/${file.name}`);
 
		if (Array.isArray(routes)) {
			for (const route of routes) {
				addRoute(fastify, route, relativeFilePath, verbose);
			}
		} else {
			addRoute(fastify, routes, relativeFilePath, verbose);
		}
	};
 
	// Process files in parallel batches
	for (let i = 0; i < validFiles.length; i += BATCH_SIZE) {
		const batch: ItemStat[] = validFiles.slice(i, i + BATCH_SIZE);
		await Promise.all(batch.map(processFile));
	}
 
	// Process subdirectories in parallel for better performance
	await Promise.all(
		folders.map(async (sub: ItemStat): Promise<void> => {
			await addFastifyRoutes(fastify, sub.fullPath, verbose);
		})
	);
};
 
export default addFastifyRoutes;