fix(admin-vite-plugin): Normalize file paths and add tests (#9595)
**What** - #9338 had a regression which caused the import path in some virtual modules to be invalid on Windows. - This PR fixes the issue so we now again create the correct import paths, and adds tests to prevent this from slipping in again.
This commit is contained in:
1 parent
84fa6ccde5
commit
813efeae51
15 files changed
+1069
-14
No files matched your search
@@ -22,14 +22,17 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup",
|
"build": "tsup",
|
||||||
"watch": "tsup --watch"
|
"watch": "tsup --watch",
|
||||||
|
"test": "vitest --run",
|
||||||
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/types": "7.25.6",
|
"@babel/types": "7.25.6",
|
||||||
"@types/node": "^20.10.4",
|
"@types/node": "^20.10.4",
|
||||||
"tsup": "8.0.1",
|
"tsup": "8.0.1",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3",
|
||||||
"vite": "^5.2.11"
|
"vite": "^5.2.11",
|
||||||
|
"vitest": "^2.1.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vite": "^5.0.0"
|
"vite": "^5.0.0"
|
||||||
|
|||||||
+3
-2
@@ -20,7 +20,7 @@ import {
|
|||||||
traverse,
|
traverse,
|
||||||
} from "../babel"
|
} from "../babel"
|
||||||
import { logger } from "../logger"
|
import { logger } from "../logger"
|
||||||
import { crawl, getParserOptions } from "../utils"
|
import { crawl, getParserOptions, normalizePath } from "../utils"
|
||||||
import { getConfigArgument, getModel, validateLink } from "./helpers"
|
import { getConfigArgument, getModel, validateLink } from "./helpers"
|
||||||
|
|
||||||
type CustomFieldDisplay = {
|
type CustomFieldDisplay = {
|
||||||
@@ -288,5 +288,6 @@ function generateCustomFieldConfigName(index: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateImport(file: string, index: number): string {
|
function generateImport(file: string, index: number): string {
|
||||||
return `import ${generateCustomFieldConfigName(index)} from "${file}"`
|
const path = normalizePath(file)
|
||||||
|
return `import ${generateCustomFieldConfigName(index)} from "${path}"`
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
traverse,
|
traverse,
|
||||||
} from "../babel"
|
} from "../babel"
|
||||||
import { logger } from "../logger"
|
import { logger } from "../logger"
|
||||||
import { crawl, getParserOptions } from "../utils"
|
import { crawl, getParserOptions, normalizePath } from "../utils"
|
||||||
import { getConfigArgument, getModel, validateLink } from "./helpers"
|
import { getConfigArgument, getModel, validateLink } from "./helpers"
|
||||||
|
|
||||||
type CustomFieldConfigField = {
|
type CustomFieldConfigField = {
|
||||||
@@ -263,7 +263,8 @@ function generateCustomFieldConfigName(index: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateImport(file: string, index: number): string {
|
function generateImport(file: string, index: number): string {
|
||||||
return `import ${generateCustomFieldConfigName(index)} from "${file}"`
|
const path = normalizePath(file)
|
||||||
|
return `import ${generateCustomFieldConfigName(index)} from "${path}"`
|
||||||
}
|
}
|
||||||
|
|
||||||
function getForms(
|
function getForms(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
traverse,
|
traverse,
|
||||||
} from "../babel"
|
} from "../babel"
|
||||||
import { logger } from "../logger"
|
import { logger } from "../logger"
|
||||||
import { crawl, getParserOptions } from "../utils"
|
import { crawl, getParserOptions, normalizePath } from "../utils"
|
||||||
import { getConfigArgument, getModel } from "./helpers"
|
import { getConfigArgument, getModel } from "./helpers"
|
||||||
|
|
||||||
type ParsedCustomFieldLink = {
|
type ParsedCustomFieldLink = {
|
||||||
@@ -138,7 +138,8 @@ function generateCustomFieldConfigName(index: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateImport(file: string, index: number): string {
|
function generateImport(file: string, index: number): string {
|
||||||
return `import ${generateCustomFieldConfigName(index)} from "${file}"`
|
const path = normalizePath(file)
|
||||||
|
return `import ${generateCustomFieldConfigName(index)} from "${path}"`
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLink(
|
function getLink(
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest"
|
||||||
|
|
||||||
|
import fs from "fs/promises"
|
||||||
|
import * as utils from "../../utils"
|
||||||
|
import { generateMenuItems } from "../generate-menu-items"
|
||||||
|
|
||||||
|
vi.mock("../../utils", async () => {
|
||||||
|
const actual = await vi.importActual("../../utils")
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
crawl: vi.fn(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
vi.mock("fs/promises", () => ({
|
||||||
|
default: {
|
||||||
|
readFile: vi.fn(),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mockFileContents = [
|
||||||
|
`
|
||||||
|
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
return <div>Page 1</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = defineRouteConfig({
|
||||||
|
label: "Page 1",
|
||||||
|
icon: "icon1",
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Page
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
return <div>Page 2</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = defineRouteConfig({
|
||||||
|
label: "Page 2",
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Page
|
||||||
|
`,
|
||||||
|
]
|
||||||
|
|
||||||
|
const expectedMenuItems = `
|
||||||
|
menuItems: [
|
||||||
|
{
|
||||||
|
label: RouteConfig0.label,
|
||||||
|
icon: RouteConfig0.icon,
|
||||||
|
path: "/one",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: RouteConfig1.label,
|
||||||
|
icon: undefined,
|
||||||
|
path: "/two",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
||||||
|
|
||||||
|
describe("generateMenuItems", () => {
|
||||||
|
it("should generate menu items", async () => {
|
||||||
|
const mockFiles = [
|
||||||
|
"Users/user/medusa/src/admin/routes/one/page.tsx",
|
||||||
|
"Users/user/medusa/src/admin/routes/two/page.tsx",
|
||||||
|
]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = await generateMenuItems(
|
||||||
|
new Set(["Users/user/medusa/src/admin"])
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result.imports).toEqual([
|
||||||
|
`import { config as RouteConfig0 } from "Users/user/medusa/src/admin/routes/one/page.tsx"`,
|
||||||
|
`import { config as RouteConfig1 } from "Users/user/medusa/src/admin/routes/two/page.tsx"`,
|
||||||
|
])
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedMenuItems)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle windows paths", async () => {
|
||||||
|
// Setup mocks
|
||||||
|
const mockFiles = [
|
||||||
|
"C:\\medusa\\src\\admin\\routes\\one\\page.tsx",
|
||||||
|
"C:\\medusa\\src\\admin\\routes\\two\\page.tsx",
|
||||||
|
]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = await generateMenuItems(new Set(["C:\\medusa\\src\\admin"]))
|
||||||
|
|
||||||
|
expect(result.imports).toEqual([
|
||||||
|
`import { config as RouteConfig0 } from "C:/medusa/src/admin/routes/one/page.tsx"`,
|
||||||
|
`import { config as RouteConfig1 } from "C:/medusa/src/admin/routes/two/page.tsx"`,
|
||||||
|
])
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedMenuItems)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest"
|
||||||
|
|
||||||
|
import { Stats } from "fs"
|
||||||
|
import fs from "fs/promises"
|
||||||
|
import * as utils from "../../utils"
|
||||||
|
import { generateRoutes } from "../generate-routes"
|
||||||
|
|
||||||
|
// Mock the dependencies
|
||||||
|
vi.mock("../../utils", async () => {
|
||||||
|
const actual = await vi.importActual("../../utils")
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
crawl: vi.fn(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
vi.mock("fs/promises", () => ({
|
||||||
|
default: {
|
||||||
|
readFile: vi.fn(),
|
||||||
|
stat: vi.fn(),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mockFileContents = [
|
||||||
|
`
|
||||||
|
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
return <div>Page 1</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = defineRouteConfig({
|
||||||
|
label: "Page 1",
|
||||||
|
icon: "icon1",
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Page
|
||||||
|
`,
|
||||||
|
`
|
||||||
|
import { defineRouteConfig } from "@medusajs/admin-sdk"
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
return <div>Page 2</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = defineRouteConfig({
|
||||||
|
label: "Page 2",
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Page
|
||||||
|
`,
|
||||||
|
]
|
||||||
|
|
||||||
|
const expectedRoutesWithoutLoaders = `
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
Component: RouteComponent0,
|
||||||
|
loader: undefined,
|
||||||
|
path: "/one",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Component: RouteComponent1,
|
||||||
|
loader: undefined,
|
||||||
|
path: "/two",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
||||||
|
|
||||||
|
const expectedRoutesWithLoaders = `
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
Component: RouteComponent0,
|
||||||
|
loader: RouteLoader0,
|
||||||
|
path: "/one",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Component: RouteComponent1,
|
||||||
|
loader: RouteLoader1,
|
||||||
|
path: "/two",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
||||||
|
|
||||||
|
describe("generateRoutes", () => {
|
||||||
|
it("should generate routes", async () => {
|
||||||
|
const mockFiles = [
|
||||||
|
"Users/user/medusa/src/admin/routes/one/page.tsx",
|
||||||
|
"Users/user/medusa/src/admin/routes/two/page.tsx",
|
||||||
|
]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
vi.mocked(fs.stat).mockRejectedValue(new Error("File not found"))
|
||||||
|
|
||||||
|
const result = await generateRoutes(
|
||||||
|
new Set(["Users/user/medusa/src/admin"])
|
||||||
|
)
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedRoutesWithoutLoaders)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should generate routes with loaders", async () => {
|
||||||
|
const mockFiles = [
|
||||||
|
"Users/user/medusa/src/admin/routes/one/page.tsx",
|
||||||
|
"Users/user/medusa/src/admin/routes/two/page.tsx",
|
||||||
|
]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
vi.mocked(fs.stat).mockResolvedValue({} as Stats) // We just want to mock that the check passes
|
||||||
|
|
||||||
|
const result = await generateRoutes(
|
||||||
|
new Set(["Users/user/medusa/src/admin"])
|
||||||
|
)
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedRoutesWithLoaders)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should handle windows paths", async () => {
|
||||||
|
const mockFiles = [
|
||||||
|
"C:\\medusa\\src\\admin\\routes\\one\\page.tsx",
|
||||||
|
"C:\\medusa\\src\\admin\\routes\\two\\page.tsx",
|
||||||
|
]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
vi.mocked(fs.stat).mockRejectedValue(new Error("File not found"))
|
||||||
|
|
||||||
|
const result = await generateRoutes(new Set(["C:\\medusa\\src\\admin"]))
|
||||||
|
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedRoutesWithoutLoaders)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -2,7 +2,12 @@ import fs from "fs/promises"
|
|||||||
import { outdent } from "outdent"
|
import { outdent } from "outdent"
|
||||||
import { isIdentifier, isObjectProperty, parse, traverse } from "../babel"
|
import { isIdentifier, isObjectProperty, parse, traverse } from "../babel"
|
||||||
import { logger } from "../logger"
|
import { logger } from "../logger"
|
||||||
import { crawl, getConfigObjectProperties, getParserOptions } from "../utils"
|
import {
|
||||||
|
crawl,
|
||||||
|
getConfigObjectProperties,
|
||||||
|
getParserOptions,
|
||||||
|
normalizePath,
|
||||||
|
} from "../utils"
|
||||||
import { getRoute } from "./helpers"
|
import { getRoute } from "./helpers"
|
||||||
|
|
||||||
type MenuItem = {
|
type MenuItem = {
|
||||||
@@ -90,7 +95,8 @@ async function parseFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateImport(file: string, index: number): string {
|
function generateImport(file: string, index: number): string {
|
||||||
return `import { config as ${generateRouteConfigName(index)} } from "${file}"`
|
const path = normalizePath(file)
|
||||||
|
return `import { config as ${generateRouteConfigName(index)} } from "${path}"`
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateMenuItem(
|
function generateMenuItem(
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
} from "./babel"
|
} from "./babel"
|
||||||
|
|
||||||
export function normalizePath(file: string) {
|
export function normalizePath(file: string) {
|
||||||
return path.normalize(file).split(path.sep).join("/")
|
return path.normalize(file.replace(/\\/g, "/"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -145,3 +145,11 @@ export function isFileInAdminSubdirectory(
|
|||||||
const normalizedPath = normalizePath(file)
|
const normalizedPath = normalizePath(file)
|
||||||
return normalizedPath.includes(`/src/admin/${subdirectory}/`)
|
return normalizedPath.includes(`/src/admin/${subdirectory}/`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test util to normalize strings, so they can be compared without taking
|
||||||
|
* whitespace into account.
|
||||||
|
*/
|
||||||
|
export function normalizeString(str: string): string {
|
||||||
|
return str.replace(/\s+/g, " ").trim()
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { vi } from "vitest"
|
||||||
|
|
||||||
|
import fs from "fs/promises"
|
||||||
|
import * as utils from "../../utils"
|
||||||
|
import { generateWidgets } from "../generate-widgets"
|
||||||
|
|
||||||
|
vi.mock("../../utils", async () => {
|
||||||
|
const actual = await vi.importActual("../../utils")
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
crawl: vi.fn(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
vi.mock("fs/promises", () => ({
|
||||||
|
default: {
|
||||||
|
readFile: vi.fn(),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const mockFileContents = [
|
||||||
|
`
|
||||||
|
import { defineWidgetConfig } from "@medusajs/admin-sdk"
|
||||||
|
|
||||||
|
const Widget = () => {
|
||||||
|
return <div>Widget 1</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = defineWidgetConfig({
|
||||||
|
zone: "product.details.after",
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Widget
|
||||||
|
`,
|
||||||
|
]
|
||||||
|
|
||||||
|
const expectedWidgets = `
|
||||||
|
widgets: [
|
||||||
|
{
|
||||||
|
Component: WidgetComponent0,
|
||||||
|
zone: ["product.details.after"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
||||||
|
|
||||||
|
describe("generateWidgets", () => {
|
||||||
|
it("should generate widgets", async () => {
|
||||||
|
const mockFiles = ["Users/user/medusa/src/admin/widgets/widget.tsx"]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = await generateWidgets(
|
||||||
|
new Set(["Users/user/medusa/src/admin"])
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result.imports).toEqual([
|
||||||
|
`import WidgetComponent0, { config as WidgetConfig0 } from "Users/user/medusa/src/admin/widgets/widget.tsx"`,
|
||||||
|
])
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedWidgets)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should handle windows paths", async () => {
|
||||||
|
const mockFiles = ["C:\\medusa\\src\\admin\\widgets\\widget.tsx"]
|
||||||
|
vi.mocked(utils.crawl).mockResolvedValue(mockFiles)
|
||||||
|
|
||||||
|
vi.mocked(fs.readFile).mockImplementation(async (file) =>
|
||||||
|
Promise.resolve(mockFileContents[mockFiles.indexOf(file as string)])
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = await generateWidgets(new Set(["C:\\medusa\\src\\admin"]))
|
||||||
|
|
||||||
|
expect(result.imports).toEqual([
|
||||||
|
`import WidgetComponent0, { config as WidgetConfig0 } from "C:/medusa/src/admin/widgets/widget.tsx"`,
|
||||||
|
])
|
||||||
|
expect(utils.normalizeString(result.code)).toEqual(
|
||||||
|
utils.normalizeString(expectedWidgets)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
getConfigObjectProperties,
|
getConfigObjectProperties,
|
||||||
getParserOptions,
|
getParserOptions,
|
||||||
hasDefaultExport,
|
hasDefaultExport,
|
||||||
|
normalizePath,
|
||||||
} from "../utils"
|
} from "../utils"
|
||||||
import { getWidgetFilesFromSources } from "./helpers"
|
import { getWidgetFilesFromSources } from "./helpers"
|
||||||
|
|
||||||
@@ -135,9 +136,10 @@ function generateWidgetConfigName(index: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateImport(file: string, index: number): string {
|
function generateImport(file: string, index: number): string {
|
||||||
|
const path = normalizePath(file)
|
||||||
return `import ${generateWidgetComponentName(
|
return `import ${generateWidgetComponentName(
|
||||||
index
|
index
|
||||||
)}, { config as ${generateWidgetConfigName(index)} } from "${file}"`
|
)}, { config as ${generateWidgetConfigName(index)} } from "${path}"`
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateWidget(zone: InjectionZone[], index: number): WidgetConfig {
|
function generateWidget(zone: InjectionZone[], index: number): WidgetConfig {
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"exclude": ["**/*.spec.ts", "vitest.config.ts", "tsup.config.ts"]
|
||||||
|
}
|
||||||
@@ -18,5 +18,5 @@
|
|||||||
"@babel/types": ["../../../node_modules/@babel/types"]
|
"@babel/types": ["../../../node_modules/@babel/types"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src", "vitest.config.ts", "tsup.config.ts"]
|
||||||
}
|
}
|
||||||
+1
@@ -2,6 +2,7 @@ import { defineConfig } from "tsup"
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
entry: ["./src/index.ts"],
|
entry: ["./src/index.ts"],
|
||||||
|
tsconfig: "tsconfig.build.json",
|
||||||
format: ["cjs", "esm"],
|
format: ["cjs", "esm"],
|
||||||
dts: true,
|
dts: true,
|
||||||
clean: true,
|
clean: true,
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from "vitest/config"
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: "node",
|
||||||
|
include: ["**/*.spec.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
||||||
|
},
|
||||||
|
})
|
||||||
Reference in new issue
Block a user