1- import express from 'express'
1+ import { readFile } from 'node:fs/promises'
2+ import { createServer } from 'node:http'
3+ import { join , extname } from 'node:path'
4+ import directoryTree from 'directory-tree'
5+ import type { DirectoryTree } from 'directory-tree'
26import sharp from 'sharp'
37import yaml from 'js-yaml'
4- import { join , extname } from 'node:path'
58import { imageSize } from 'image-size'
6- import directoryTree , { DirectoryTree } from 'directory-tree'
7- import { readFileSync } from 'fs'
8-
9- const app = express ( )
109
1110type Meta = Partial < {
1211 title : string
@@ -42,6 +41,7 @@ const cleanBasePath = (input?: DirectoryWithMeta): DirectoryWithMeta | undefined
4241 ...input ,
4342 name : removeBasePath ( input . name ) ,
4443 path : removeBasePath ( input . path ) ,
44+ // @ts -expect-error typescript is not able to pull the typing
4545 children : input ?. children ?. map ( cleanBasePath ) ,
4646 }
4747}
@@ -50,13 +50,20 @@ const sortChildren = (input?: DirectoryWithMeta): DirectoryWithMeta | undefined
5050 if ( ! input ?. children ?. length ) return input
5151 return {
5252 ...input ,
53+ // @ts -expect-error typescript is not able to pull the typing
5354 children : input ?. children ?. sort ( ( a , b ) => ( a . name < b . name ? - 1 : 1 ) ) . map ( sortChildren ) ,
5455 }
5556}
5657
5758const extractImageSize = ( input ?: DirectoryWithMeta ) : DirectoryWithMeta | undefined => {
5859 if ( ! input ) return
59- if ( input ?. children ?. length ) return { ...input , children : input . children ?. map ( extractImageSize ) }
60+ if ( input ?. children ?. length ) {
61+ return {
62+ ...input ,
63+ // @ts -expect-error typescript is not able to pull the typing
64+ children : input . children ?. map ( extractImageSize ) ,
65+ }
66+ }
6067 const extension = extname ( input . name || '' )
6168 const isImage = extension && IMAGE_EXTENSIONS . includes ( extension )
6269 if ( ! isImage ) return input
@@ -70,17 +77,15 @@ const getMetaContents = async (input: DirectoryTree): Promise<Meta | undefined>
7077 const metaItem = input ?. children ?. find ( x => META_FILE_NAMES . includes ( x . name ) )
7178 const isJson = metaItem ?. name . endsWith ( '.json' )
7279 if ( ! metaItem ) return
73- const fileContent = readFileSync ( metaItem . path , 'utf-8' )
80+ const fileContent = await readFile ( metaItem . path , 'utf-8' )
7481 if ( isJson ) return JSON . parse ( fileContent )
7582 return yaml . load ( fileContent ) as Meta | undefined
7683 } catch {
7784 return
7885 }
7986}
8087
81- const extractMeta = async (
82- input : DirectoryTree & { meta ?: Meta } ,
83- ) : Promise < DirectoryTree & { meta ?: Meta } > => {
88+ const extractMeta = async ( input : DirectoryTree ) : Promise < DirectoryWithMeta > => {
8489 const meta = await getMetaContents ( input )
8590 const extracted = input . children ?. length
8691 ? await Promise . all ( input . children ?. map ( item => extractMeta ( item ) ) )
@@ -92,52 +97,58 @@ const extractMeta = async (
9297const initializeServer = async ( ) => {
9398 const treeWithMeta = await extractMeta ( tree )
9499
95- app . get ( '*' , async ( req , res ) => {
96- const pathname = req . path
100+ const server = createServer ( async ( req , res ) => {
101+ const url = new URL ( req . url ! , `http://${ req . headers . host } ` )
102+ const pathname = url . pathname
97103 const depth = pathname . split ( '/' ) . filter ( x => ! ! x ) . length
98104 const pathType = PATH_TYPE_BY_DEPTH [ depth ]
99105
100106 switch ( pathType ) {
101107 case 'root' :
102108 case 'page' :
103- case 'section' :
109+ case 'section' : {
104110 const result = sortChildren (
105111 cleanBasePath ( extractImageSize ( subtree ( pathname . split ( '/' ) ) ( treeWithMeta ) ) ) ,
106112 )
107- return res . json ( result )
113+ res . writeHead ( 200 , { 'Content-Type' : 'application/json' } )
114+ return res . end ( JSON . stringify ( result , null , 2 ) )
115+ }
108116
109- case 'file' :
117+ case 'file' : {
110118 const filePath = decodeURIComponent ( join ( BASE_PATH , pathname ) )
111119 try {
112- const height = Number . parseInt ( req . query . h as string ) || undefined
113- const width = Number . parseInt ( req . query . w as string ) || undefined
114- const quality = Number . parseInt ( req . query . q as string ) || undefined
120+ const height = Number . parseInt ( url . searchParams . get ( 'h' ) || '' ) || undefined
121+ const width = Number . parseInt ( url . searchParams . get ( 'w' ) || '' ) || undefined
122+ const quality = Number . parseInt ( url . searchParams . get ( 'q' ) || '' ) || undefined
115123 const hasParameters = ! ! height || ! ! width || ! ! quality
116124
117125 if ( ! hasParameters ) {
118- return res . sendFile ( filePath , { root : process . cwd ( ) } )
126+ const fileContent = await readFile ( filePath )
127+ res . writeHead ( 200 , { 'Content-Type' : 'image/jpeg' } )
128+ return res . end ( fileContent )
119129 }
120130
121- const imageBuffer = readFileSync ( filePath )
131+ const imageBuffer = await readFile ( filePath )
122132 const compressed = await sharp ( imageBuffer )
123133 . resize ( { height, width, withoutEnlargement : true } )
124134 . jpeg ( { quality } )
125135 . toBuffer ( )
126136
127- res . contentType ( ' image/jpeg')
128- return res . send ( compressed )
137+ res . writeHead ( 200 , { 'Content-Type' : ' image/jpeg' } )
138+ return res . end ( compressed )
129139 } catch ( error ) {
130- return res . status ( 404 ) . send ( '404' )
140+ res . writeHead ( 404 )
141+ return res . end ( '404' )
131142 }
143+ }
132144
133145 default :
134- return res . status ( 404 ) . send ( '404' )
146+ res . writeHead ( 404 )
147+ return res . end ( '404' )
135148 }
136149 } )
137150
138- app . listen ( 3001 , ( ) => {
139- console . log ( 'Server running on port 3001' )
140- } )
151+ server . listen ( 3001 , ( ) => console . log ( 'Server running on port 3001' ) )
141152}
142153
143154initializeServer ( ) . catch ( console . error )
0 commit comments