fix(framework): handle deprecated Dirent path (#10179)
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: https://github.com/medusajs/medusa/issues/8419
This commit is contained in:
committed by
GitHub
parent
ec1ab4db87
commit
42c08fa8e0
6
.changeset/new-eels-drop.md
Normal file
6
.changeset/new-eels-drop.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@medusajs/framework": patch
|
||||
"@medusajs/utils": patch
|
||||
---
|
||||
|
||||
Fix loaders path
|
||||
@@ -1,3 +1,4 @@
|
||||
import { trackFeatureFlag } from "@medusajs/telemetry"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
dynamicImport,
|
||||
@@ -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({})
|
||||
|
||||
@@ -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) {
|
||||
await readDirRecursive(flagDir).then(async (files) => {
|
||||
if (!files?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
files.map(async (file) => {
|
||||
if (file.isDirectory()) {
|
||||
return await featureFlagsLoader(join(flagDir, file.name))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
const fileExports = await dynamicImport(join(flagDir, file.name))
|
||||
const featureFlag = fileExports.default
|
||||
|
||||
if (!featureFlag) {
|
||||
return
|
||||
}
|
||||
|
||||
registerFlag(featureFlag, projectConfigFlags)
|
||||
if (!featureFlag) {
|
||||
return
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
registerFlag(featureFlag, projectConfigFlags)
|
||||
return
|
||||
})
|
||||
})
|
||||
|
||||
return featureFlagRouter
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
dynamicImport,
|
||||
parseCorsOrigins,
|
||||
promiseAll,
|
||||
readDirRecursive,
|
||||
resolveExports,
|
||||
wrapHandler,
|
||||
} from "@medusajs/utils"
|
||||
@@ -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"
|
||||
@@ -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,
|
||||
""
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
/**
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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"
|
||||
@@ -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() &&
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
/**
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,3 @@
|
||||
import { dirname, join } from "path"
|
||||
import {
|
||||
constants,
|
||||
type Dirent,
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
|
||||
23
packages/core/utils/src/common/read-dir-recursive.ts
Normal file
23
packages/core/utils/src/common/read-dir-recursive.ts
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user