Skip to content

Commit af49b10

Browse files
fix(ui~cli): windows path normalization for setup plugins (#1541)
* refactor(cli): windows support - replace path.join with joinNormalizedPath in plugin setup commands * chore: add changeset
1 parent 6caecce commit af49b10

17 files changed

+100
-27
lines changed

.changeset/shiny-parents-raise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"flowbite-react": patch
3+
---
4+
5+
fix(ui~cli): path normalzation for windows support (setup plugins paths)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginAstro(configPath: string) {
66
await addPluginToConfig({
77
configKey: "integrations",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "astro"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "astro"),
1010
pluginName,
1111
});
1212
}

packages/ui/src/cli/commands/plugins/setup-plugin-bun.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import fs from "fs/promises";
2-
import path from "path";
32
import toml from "@iarna/toml";
43
import { pluginName, pluginPath } from "../../consts";
4+
import { joinNormalizedPath } from "../../utils/normalize-path";
55
import { updateBuildConfig } from "../../utils/update-build-config";
66

77
export async function setupPluginBun(configPath: string) {
88
try {
99
// update bunfig.toml
1010
const bunfig = await fs.readFile(configPath, "utf-8");
1111
const bunfigContent = toml.parse(bunfig) as { serve?: { static?: { plugins?: string[] } } };
12-
const bunPluginPath = path.join(pluginPath, "bun");
12+
const bunPluginPath = joinNormalizedPath(pluginPath, "bun");
1313

1414
if (bunfigContent.serve?.static?.plugins?.includes(pluginName)) {
1515
return;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginFarm(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "farm"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "farm"),
1010
pluginName,
1111
});
1212
}

packages/ui/src/cli/commands/plugins/setup-plugin-modernjs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import fs from "fs/promises";
2-
import path from "path";
32
import cjson from "comment-json";
43
import { pluginName, pluginPath } from "../../consts";
54
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
5+
import { joinNormalizedPath } from "../../utils/normalize-path";
66

77
export async function setupPluginModernjs(configPath: string) {
88
await addPluginToConfig({
99
configKey: "plugins",
1010
configPath,
11-
pluginImportPath: path.join(pluginPath, "modernjs"),
11+
pluginImportPath: joinNormalizedPath(pluginPath, "modernjs"),
1212
pluginName,
1313
});
1414

packages/ui/src/cli/commands/plugins/setup-plugin-nextjs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from "fs/promises";
2-
import path from "path";
32
import { pluginPath } from "../../consts";
43
import { addImport } from "../../utils/add-import";
4+
import { joinNormalizedPath } from "../../utils/normalize-path";
55
import { wrapDefaultExport } from "../../utils/wrap-default-export";
66

77
export async function setupPluginNextjs(configPath: string) {
@@ -13,7 +13,7 @@ export async function setupPluginNextjs(configPath: string) {
1313
let updatedContent = addImport({
1414
content,
1515
importName: pluginName,
16-
importPath: path.join(pluginPath, "nextjs"),
16+
importPath: joinNormalizedPath(pluginPath, "nextjs"),
1717
});
1818

1919
if (!content.includes(`${pluginName}(`)) {

packages/ui/src/cli/commands/plugins/setup-plugin-parcel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fs from "fs/promises";
22
import path from "path";
33
import { outputDir, pluginName, pluginPath } from "../../consts";
4+
import { joinNormalizedPath } from "../../utils/normalize-path";
45

56
export async function setupPluginParcel(configPath: string) {
67
try {
@@ -38,7 +39,7 @@ export async function setupPluginParcel(configPath: string) {
3839
}
3940

4041
// setup `.flowbite-react/parcel-config/parcel-reporter.cjs` file
41-
const pluginImportPath = path.join(pluginPath, "parcel");
42+
const pluginImportPath = joinNormalizedPath(pluginPath, "parcel");
4243
const parcelReporterFileContent = `module.exports = require("${pluginImportPath}");`;
4344
const parcelReporterFilePath = path.join(parcelConfigDir, parcelReporterFile);
4445

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginRolldown(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "rolldown"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "rolldown"),
1010
pluginName,
1111
});
1212
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginRollup(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "rollup"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "rollup"),
1010
pluginName,
1111
});
1212
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginRsbuild(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "rsbuild"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "rsbuild"),
1010
pluginName,
1111
});
1212
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginRspack(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "rspack"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "rspack"),
1010
pluginName,
1111
});
1212
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginTanStackStart(configPath: string) {
66
await addPluginToConfig({
77
configKey: "vite.plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "vite"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "vite"),
1010
pluginName,
1111
});
1212
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginVite(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "vite"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "vite"),
1010
pluginName,
1111
});
1212
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import path from "path";
21
import { pluginName, pluginPath } from "../../consts";
32
import { addPluginToConfig } from "../../utils/add-plugin-to-config";
3+
import { joinNormalizedPath } from "../../utils/normalize-path";
44

55
export async function setupPluginWebpack(configPath: string) {
66
await addPluginToConfig({
77
configKey: "plugins",
88
configPath,
9-
pluginImportPath: path.join(pluginPath, "webpack"),
9+
pluginImportPath: joinNormalizedPath(pluginPath, "webpack"),
1010
pluginName,
1111
});
1212
}

packages/ui/src/cli/commands/setup-tailwind.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { classListFilePath, excludeDirs, pluginName, pluginPath } from "../const
44
import { addImport } from "../utils/add-import";
55
import { addToConfig } from "../utils/add-to-config";
66
import { findFiles } from "../utils/find-files";
7+
import { joinNormalizedPath } from "../utils/normalize-path";
78

89
export async function setupTailwind() {
910
try {
@@ -56,7 +57,7 @@ async function setupTailwindV4() {
5657

5758
found = true;
5859

59-
const pluginDirectivePath = path.join(pluginPath, "tailwindcss");
60+
const pluginDirectivePath = joinNormalizedPath(pluginPath, "tailwindcss");
6061
const sourceDirectivePath = path
6162
.join(path.relative(path.dirname(file), process.cwd()), classListFilePath)
6263
.replace(/\\/g, "/");
@@ -118,7 +119,7 @@ async function setupTailwindV3() {
118119
let updatedContent = addImport({
119120
content,
120121
importName: pluginName,
121-
importPath: path.join(pluginPath, "tailwindcss"),
122+
importPath: joinNormalizedPath(pluginPath, "tailwindcss"),
122123
});
123124

124125
updatedContent = addToConfig({
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { describe, expect, it } from "vitest";
2+
import { joinNormalizedPath, normalizeImportPath } from "../normalize-path";
3+
4+
describe("normalizeImportPath", () => {
5+
it("should normalize Windows-style paths to use forward slashes", () => {
6+
expect(normalizeImportPath("path\\to\\file")).toBe("path/to/file");
7+
expect(normalizeImportPath("C:\\Users\\name\\project")).toBe("C:/Users/name/project");
8+
});
9+
10+
it("should leave Unix-style paths unchanged", () => {
11+
expect(normalizeImportPath("path/to/file")).toBe("path/to/file");
12+
expect(normalizeImportPath("/home/user/project")).toBe("/home/user/project");
13+
});
14+
15+
it("should handle mixed path separators", () => {
16+
expect(normalizeImportPath("path\\to/file")).toBe("path/to/file");
17+
expect(normalizeImportPath("C:/Users\\name/project")).toBe("C:/Users/name/project");
18+
});
19+
20+
it("should handle paths with no separators", () => {
21+
expect(normalizeImportPath("file")).toBe("file");
22+
});
23+
});
24+
25+
describe("joinNormalizedPath", () => {
26+
it("should join path segments and normalize to forward slashes", () => {
27+
expect(joinNormalizedPath("path", "to", "file")).toBe("path/to/file");
28+
expect(joinNormalizedPath("C:", "Users", "name", "project")).toBe("C:/Users/name/project");
29+
});
30+
31+
it("should handle single segment", () => {
32+
expect(joinNormalizedPath("file")).toBe("file");
33+
});
34+
35+
it("should handle empty segments", () => {
36+
expect(joinNormalizedPath("path", "", "file")).toBe("path/file");
37+
});
38+
39+
it("should handle segments with existing separators", () => {
40+
expect(joinNormalizedPath("path\\to", "file")).toBe("path/to/file");
41+
expect(joinNormalizedPath("path/to", "file")).toBe("path/to/file");
42+
});
43+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import path from "path";
2+
3+
/**
4+
* Normalizes a path for use in import statements, ensuring forward slashes are used
5+
* regardless of the operating system.
6+
*
7+
* @param importPath - The path to normalize
8+
* @returns The normalized path with forward slashes
9+
*/
10+
export function normalizeImportPath(importPath: string): string {
11+
return importPath.replace(/\\/g, "/");
12+
}
13+
14+
/**
15+
* Joins path segments and normalizes the result to use forward slashes.
16+
* This is useful for paths that need to be used in import statements or URLs.
17+
*
18+
* @param segments - Path segments to join
19+
* @returns The normalized path with forward slashes
20+
*/
21+
export function joinNormalizedPath(...segments: string[]): string {
22+
return normalizeImportPath(path.join(...segments));
23+
}

0 commit comments

Comments
 (0)