Skip to content

Commit

Permalink
fix(framework): handle deprecated Dirent path (#10179)
Browse files Browse the repository at this point in the history
What:

- `Dirent` class from `NodeJS` has different properties in different versions, causing issues in our loaders.
- Util `readDirRecursive` was introduced, avoiding old node versions to break

FIXES: #8419
  • Loading branch information
carlos-r-l-rodrigues authored Nov 20, 2024
1 parent ec1ab4d commit 42c08fa
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 73 deletions.
6 changes: 6 additions & 0 deletions .changeset/new-eels-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@medusajs/framework": patch
"@medusajs/utils": patch
---

Fix loaders path
58 changes: 28 additions & 30 deletions packages/core/framework/src/feature-flags/feature-flag-loader.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { trackFeatureFlag } from "@medusajs/telemetry"
import {
ContainerRegistrationKeys,
dynamicImport,
Expand All @@ -7,15 +8,14 @@ import {
isString,
isTruthy,
objectFromStringPath,
readDirRecursive,
} from "@medusajs/utils"
import { trackFeatureFlag } from "@medusajs/telemetry"
import { asFunction } from "awilix"
import { join, normalize } from "path"
import { configManager } from "../config"
import { container } from "../container"
import { logger } from "../logger"
import { FlagSettings } from "./types"
import { container } from "../container"
import { asFunction } from "awilix"
import { configManager } from "../config"
import { readdir } from "fs/promises"

export const featureFlagRouter = new FlagRouter({})

Expand Down Expand Up @@ -95,36 +95,34 @@ export async function featureFlagsLoader(

const flagDir = normalize(sourcePath)

await readdir(flagDir, { recursive: true, withFileTypes: true }).then(
async (files) => {
if (!files?.length) {
return
}

files.map(async (file) => {
if (file.isDirectory()) {
return await featureFlagsLoader(join(flagDir, file.name))
}
await readDirRecursive(flagDir).then(async (files) => {
if (!files?.length) {
return
}

if (
excludedExtensions.some((ext) => file.name.endsWith(ext)) ||
excludedFiles.includes(file.name)
) {
return
}
files.map(async (file) => {
if (file.isDirectory()) {
return await featureFlagsLoader(join(flagDir, file.name))
}

const fileExports = await dynamicImport(join(flagDir, file.name))
const featureFlag = fileExports.default
if (
excludedExtensions.some((ext) => file.name.endsWith(ext)) ||
excludedFiles.includes(file.name)
) {
return
}

if (!featureFlag) {
return
}
const fileExports = await dynamicImport(join(flagDir, file.name))
const featureFlag = fileExports.default

registerFlag(featureFlag, projectConfigFlags)
if (!featureFlag) {
return
})
}
)
}

registerFlag(featureFlag, projectConfigFlags)
return
})
})

return featureFlagRouter
}
11 changes: 5 additions & 6 deletions packages/core/framework/src/http/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
dynamicImport,
parseCorsOrigins,
promiseAll,
readDirRecursive,
resolveExports,
wrapHandler,
} from "@medusajs/utils"
Expand All @@ -14,6 +15,7 @@ import {
text,
urlencoded,
} from "express"
import { Dirent } from "fs"
import { readdir } from "fs/promises"
import { extname, join, parse, sep } from "path"
import { configManager } from "../config"
Expand Down Expand Up @@ -527,11 +529,8 @@ export class ApiRoutesLoader {

protected async createRoutesMap(): Promise<void> {
await promiseAll(
await readdir(this.#sourceDir, {
recursive: true,
withFileTypes: true,
}).then((entries) => {
const fileEntries = entries.filter((entry) => {
await readDirRecursive(this.#sourceDir).then((entries) => {
const fileEntries = entries.filter((entry: Dirent) => {
const fullPathFromSource = join(entry.path, entry.name).replace(
this.#sourceDir,
""
Expand All @@ -549,7 +548,7 @@ export class ApiRoutesLoader {
)
})

return fileEntries.map(async (entry) => {
return fileEntries.map(async (entry: Dirent) => {
const path = join(entry.path, entry.name)
return this.createRoutesDescriptor(path)
})
Expand Down
13 changes: 6 additions & 7 deletions packages/core/framework/src/jobs/job-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
isObject,
MedusaError,
promiseAll,
readDirRecursive,
} from "@medusajs/utils"
import {
createStep,
createWorkflow,
StepResponse,
} from "@medusajs/workflows-sdk"
import { access, readdir } from "fs/promises"
import { Dirent } from "fs"
import { access } from "fs/promises"
import { join } from "path"
import { logger } from "../logger"

Expand Down Expand Up @@ -138,11 +140,8 @@ export class JobLoader {
return
}

return await readdir(sourcePath, {
recursive: true,
withFileTypes: true,
}).then(async (entries) => {
const fileEntries = entries.filter((entry) => {
return await readDirRecursive(sourcePath).then(async (entries) => {
const fileEntries = entries.filter((entry: Dirent) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(entry.name))
Expand All @@ -152,7 +151,7 @@ export class JobLoader {
logger.debug(`Registering jobs from ${sourcePath}.`)

return await promiseAll(
fileEntries.map(async (entry) => {
fileEntries.map(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)

const module_ = await dynamicImport(fullPath)
Expand Down
16 changes: 7 additions & 9 deletions packages/core/framework/src/links/link-loader.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { dynamicImport, promiseAll } from "@medusajs/utils"
import { logger } from "../logger"
import { access, readdir } from "fs/promises"
import { dynamicImport, promiseAll, readDirRecursive } from "@medusajs/utils"
import { Dirent } from "fs"
import { access } from "fs/promises"
import { join } from "path"
import { logger } from "../logger"

export class LinkLoader {
/**
Expand Down Expand Up @@ -43,11 +44,8 @@ export class LinkLoader {
return
}

return await readdir(sourcePath, {
recursive: true,
withFileTypes: true,
}).then(async (entries) => {
const fileEntries = entries.filter((entry) => {
return await readDirRecursive(sourcePath).then(async (entries) => {
const fileEntries = entries.filter((entry: Dirent) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(entry.name))
Expand All @@ -57,7 +55,7 @@ export class LinkLoader {
logger.debug(`Registering links from ${sourcePath}.`)

return await promiseAll(
fileEntries.map(async (entry) => {
fileEntries.map(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
return await dynamicImport(fullPath)
})
Expand Down
11 changes: 5 additions & 6 deletions packages/core/framework/src/subscribers/subscriber-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import {
kebabCase,
Modules,
promiseAll,
readDirRecursive,
resolveExports,
} from "@medusajs/utils"
import { access, readdir } from "fs/promises"
import { access } from "fs/promises"
import { join, parse } from "path"

import { Dirent } from "fs"
import { configManager } from "../config"
import { container } from "../container"
import { logger } from "../logger"
Expand Down Expand Up @@ -137,10 +139,7 @@ export class SubscriberLoader {
}

private async createMap(dirPath: string) {
const promises = await readdir(dirPath, {
recursive: true,
withFileTypes: true,
}).then(async (entries) => {
const promises = await readDirRecursive(dirPath).then(async (entries) => {
const fileEntries = entries.filter((entry) => {
return (
!entry.isDirectory() &&
Expand All @@ -150,7 +149,7 @@ export class SubscriberLoader {

logger.debug(`Registering subscribers from ${dirPath}.`)

return fileEntries.flatMap(async (entry) => {
return fileEntries.flatMap(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
return await this.createDescriptor(fullPath)
})
Expand Down
16 changes: 7 additions & 9 deletions packages/core/framework/src/workflows/workflow-loader.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { dynamicImport, promiseAll } from "@medusajs/utils"
import { logger } from "../logger"
import { access, readdir } from "fs/promises"
import { dynamicImport, promiseAll, readDirRecursive } from "@medusajs/utils"
import { Dirent } from "fs"
import { access } from "fs/promises"
import { join } from "path"
import { logger } from "../logger"

export class WorkflowLoader {
/**
Expand Down Expand Up @@ -43,11 +44,8 @@ export class WorkflowLoader {
return
}

return await readdir(sourcePath, {
recursive: true,
withFileTypes: true,
}).then(async (entries) => {
const fileEntries = entries.filter((entry) => {
return await readDirRecursive(sourcePath).then(async (entries) => {
const fileEntries = entries.filter((entry: Dirent) => {
return (
!entry.isDirectory() &&
!this.#excludes.some((exclude) => exclude.test(entry.name))
Expand All @@ -57,7 +55,7 @@ export class WorkflowLoader {
logger.debug(`Registering workflows from ${sourcePath}.`)

return await promiseAll(
fileEntries.map(async (entry) => {
fileEntries.map(async (entry: Dirent) => {
const fullPath = join(entry.path, entry.name)
return await dynamicImport(fullPath)
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { readdir } from "fs/promises"
import { join } from "path"
import { readDirRecursive } from "../read-dir-recursive"

jest.mock("fs/promises")
jest.mock("path")

describe("readDirRecursive", () => {
it("should recursively read directories and return all entries", async () => {
const mockReaddir = readdir as jest.MockedFunction<typeof readdir>
const mockJoin = join as jest.MockedFunction<typeof join>

// dir structure
const dirStructure = {
"/root": [
{ name: "file1.txt", isDirectory: () => false },
{ name: "subdir", isDirectory: () => true },
],
"/root/subdir": [
{ name: "file2.txt", isDirectory: () => false },
{ name: "nested", isDirectory: () => true },
],
"/root/subdir/nested": [{ name: "file3.txt", isDirectory: () => false }],
}

mockReaddir.mockImplementation((dir) => {
return dirStructure[dir as string] ?? []
})
mockJoin.mockImplementation((...paths) => paths.join("/"))

const result = await readDirRecursive("/root")

expect(result).toEqual([
{ name: "file1.txt", isDirectory: expect.any(Function), path: "/root" },
{ name: "subdir", isDirectory: expect.any(Function), path: "/root" },
{
name: "file2.txt",
isDirectory: expect.any(Function),
path: "/root/subdir",
},
{
name: "nested",
isDirectory: expect.any(Function),
path: "/root/subdir",
},
{
name: "file3.txt",
isDirectory: expect.any(Function),
path: "/root/subdir/nested",
},
])

expect(mockReaddir).toHaveBeenCalledWith("/root", { withFileTypes: true })
expect(mockReaddir).toHaveBeenCalledWith("/root/subdir", {
withFileTypes: true,
})
expect(mockReaddir).toHaveBeenCalledWith("/root/subdir/nested", {
withFileTypes: true,
})
})
})
10 changes: 4 additions & 6 deletions packages/core/utils/src/common/file-system.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { dirname, join } from "path"
import {
constants,
type Dirent,
Expand All @@ -8,8 +7,10 @@ import {
type StatOptions,
type WriteFileOptions,
} from "fs"
import { dirname, join } from "path"
import { readDirRecursive } from "./read-dir-recursive"

const { rm, stat, mkdir, access, readdir, readFile, writeFile } = promises
const { rm, stat, mkdir, access, readFile, writeFile } = promises

export type JSONFileOptions = WriteFileOptions & {
spaces?: number | string
Expand Down Expand Up @@ -127,10 +128,7 @@ export class FileSystem {
*/
readDir(dirPath?: string): Promise<Dirent[]> {
const location = dirPath ? this.makePath(dirPath) : this.basePath
return readdir(location, {
recursive: true,
withFileTypes: true,
})
return readDirRecursive(location)
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/core/utils/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export * from "./pick-value-from-object"
export * from "./plurailze"
export * from "./prefix-array-items"
export * from "./promise-all"
export * from "./read-dir-recursive"
export * from "./remote-query-object-from-string"
export * from "./remote-query-object-to-string"
export * from "./remove-nullisih"
Expand Down
23 changes: 23 additions & 0 deletions packages/core/utils/src/common/read-dir-recursive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Dirent } from "fs"
import { readdir } from "fs/promises"
import { join } from "path"

export async function readDirRecursive(dir: string): Promise<Dirent[]> {
let allEntries: Dirent[] = []
const readRecursive = async (dir) => {
const entries = await readdir(dir, { withFileTypes: true })

for (const entry of entries) {
const fullPath = join(dir, entry.name)
entry.path = dir
allEntries.push(entry)

if (entry.isDirectory()) {
await readRecursive(fullPath)
}
}
}

await readRecursive(dir)
return allEntries
}

0 comments on commit 42c08fa

Please sign in to comment.