fix(build): address review comments and add unit tests for additionalFiles
- Fix getGlobBase to return '.' for single-part patterns like 'file.txt' - Fix Windows path separator handling by using 'sep' instead of 'posix.sep' when splitting - Export getGlobBase function for testing - Add comprehensive unit tests for getGlobBase function - Add vitest configuration for @trigger.dev/build package Co-authored-by: Eric Allam <ericallam@users.noreply.github.com>
This commit is contained in:
@@ -74,7 +74,9 @@
|
||||
"dev": "tshy --watch",
|
||||
"typecheck": "tsc --noEmit -p tsconfig.src.json",
|
||||
"update-version": "tsx ../../scripts/updateVersion.ts",
|
||||
"check-exports": "attw --pack ."
|
||||
"check-exports": "attw --pack .",
|
||||
"test": "vitest run",
|
||||
"test:dev": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/config": "^6.10.0",
|
||||
@@ -91,7 +93,8 @@
|
||||
"esbuild": "^0.23.0",
|
||||
"rimraf": "6.0.1",
|
||||
"tshy": "^3.0.2",
|
||||
"tsx": "4.17.0"
|
||||
"tsx": "4.17.0",
|
||||
"vitest": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.20.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BuildManifest } from "@trigger.dev/core/v3";
|
||||
import { BuildContext } from "@trigger.dev/core/v3/build";
|
||||
import { copyFile, mkdir } from "node:fs/promises";
|
||||
import { dirname, isAbsolute, join, posix, relative, resolve } from "node:path";
|
||||
import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
||||
import { glob } from "tinyglobby";
|
||||
|
||||
export type AdditionalFilesOptions = {
|
||||
@@ -76,7 +76,8 @@ async function findStaticAssetFiles(
|
||||
// Extracts the base directory from a glob pattern (the non-wildcard prefix).
|
||||
// For example: "../shared/**" -> "../shared", "./assets/*.txt" -> "./assets"
|
||||
// For specific files without globs: "./config/settings.json" -> "./config" (parent dir)
|
||||
function getGlobBase(pattern: string): string {
|
||||
// For single-part patterns: "file.txt" -> "." (current dir)
|
||||
export function getGlobBase(pattern: string): string {
|
||||
const parts = pattern.split(/[/\\]/);
|
||||
const baseParts: string[] = [];
|
||||
let hasGlobCharacters = false;
|
||||
@@ -92,8 +93,9 @@ function getGlobBase(pattern: string): string {
|
||||
|
||||
// If no glob characters were found, the pattern is a specific file path.
|
||||
// Return the parent directory so that relative() preserves the filename.
|
||||
if (!hasGlobCharacters && baseParts.length > 1) {
|
||||
baseParts.pop(); // Remove the filename, keep the directory
|
||||
// For single-part patterns (just a filename), return "." to indicate current directory.
|
||||
if (!hasGlobCharacters) {
|
||||
baseParts.pop(); // Remove the filename, keep the directory (or empty for single-part)
|
||||
}
|
||||
|
||||
return baseParts.length > 0 ? baseParts.join(posix.sep) : ".";
|
||||
@@ -129,8 +131,9 @@ async function findStaticAssetsForMatcher(
|
||||
pathInsideDestinationDir = join(options.destination, relativeToGlobBase);
|
||||
} else {
|
||||
// Default behavior: compute relative path from cwd and strip ".." segments
|
||||
// Use platform-specific separator for splitting since path.relative() returns platform separators
|
||||
pathInsideDestinationDir = relative(cwd, file)
|
||||
.split(posix.sep)
|
||||
.split(sep)
|
||||
.filter((p) => p !== "..")
|
||||
.join(posix.sep);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { getGlobBase } from "../src/internal/additionalFiles.js";
|
||||
|
||||
describe("getGlobBase", () => {
|
||||
describe("glob patterns with wildcards", () => {
|
||||
it("extracts base from parent directory glob pattern", () => {
|
||||
expect(getGlobBase("../shared/**")).toBe("../shared");
|
||||
});
|
||||
|
||||
it("extracts base from relative directory glob pattern", () => {
|
||||
expect(getGlobBase("./assets/*.txt")).toBe("./assets");
|
||||
});
|
||||
|
||||
it("extracts base from nested directory glob pattern", () => {
|
||||
expect(getGlobBase("files/nested/**/*.js")).toBe("files/nested");
|
||||
});
|
||||
|
||||
it("returns current directory for top-level glob", () => {
|
||||
expect(getGlobBase("**/*.js")).toBe(".");
|
||||
});
|
||||
|
||||
it("returns current directory for star pattern", () => {
|
||||
expect(getGlobBase("*.js")).toBe(".");
|
||||
});
|
||||
|
||||
it("handles question mark wildcard", () => {
|
||||
expect(getGlobBase("./src/?/*.ts")).toBe("./src");
|
||||
});
|
||||
|
||||
it("handles bracket patterns", () => {
|
||||
expect(getGlobBase("./src/[abc]/*.ts")).toBe("./src");
|
||||
});
|
||||
|
||||
it("handles brace expansion patterns", () => {
|
||||
expect(getGlobBase("./src/{a,b}/*.ts")).toBe("./src");
|
||||
});
|
||||
|
||||
it("handles deeply nested patterns", () => {
|
||||
expect(getGlobBase("a/b/c/d/**")).toBe("a/b/c/d");
|
||||
});
|
||||
});
|
||||
|
||||
describe("specific file paths without globs", () => {
|
||||
it("returns parent directory for file in subdirectory", () => {
|
||||
expect(getGlobBase("./config/settings.json")).toBe("./config");
|
||||
});
|
||||
|
||||
it("returns parent directory for file in nested subdirectory", () => {
|
||||
expect(getGlobBase("../shared/utils/helpers.ts")).toBe("../shared/utils");
|
||||
});
|
||||
|
||||
it("returns current directory for single-part filename", () => {
|
||||
expect(getGlobBase("file.txt")).toBe(".");
|
||||
});
|
||||
|
||||
it("returns current directory for filename starting with dot", () => {
|
||||
expect(getGlobBase(".env")).toBe(".");
|
||||
});
|
||||
|
||||
it("returns parent directory for explicit relative path to file", () => {
|
||||
expect(getGlobBase("./file.txt")).toBe(".");
|
||||
});
|
||||
|
||||
it("returns parent directories for parent reference to file", () => {
|
||||
expect(getGlobBase("../file.txt")).toBe("..");
|
||||
});
|
||||
|
||||
it("handles multiple parent references", () => {
|
||||
expect(getGlobBase("../../config/app.json")).toBe("../../config");
|
||||
});
|
||||
});
|
||||
|
||||
describe("edge cases", () => {
|
||||
it("returns current directory for empty string", () => {
|
||||
expect(getGlobBase("")).toBe(".");
|
||||
});
|
||||
|
||||
it("handles Windows-style backslashes", () => {
|
||||
expect(getGlobBase("..\\shared\\**")).toBe("../shared");
|
||||
});
|
||||
|
||||
it("handles mixed forward and back slashes", () => {
|
||||
expect(getGlobBase("../shared\\nested/**")).toBe("../shared/nested");
|
||||
});
|
||||
|
||||
it("handles patterns with only dots", () => {
|
||||
expect(getGlobBase("./")).toBe(".");
|
||||
});
|
||||
|
||||
it("handles parent directory reference only", () => {
|
||||
expect(getGlobBase("../")).toBe("..");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["test/**/*.test.ts", "src/**/*.test.ts"],
|
||||
globals: true,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user