mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-09 04:22:07 +00:00
[fs-detectors] Use LocalFileSystemDetector instead of FixtureFilesystem (#10100)
The code for these two are almost identical, so consolidate into one codebase. Also adjusts the `pnpm test` script to allow for specifying a file name to be executed, instead of running all tests.
This commit is contained in:
5
.changeset/calm-apes-double.md
Normal file
5
.changeset/calm-apes-double.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@vercel/fs-detectors': major
|
||||
---
|
||||
|
||||
`LocalFileSystemDetector#readdir()` now returns paths relative to the root dir, instead of absolute paths. This is to align with the usage of the detectors that are using the `DetectorFilesystem` interface.
|
||||
@@ -15,8 +15,8 @@
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest --env node --verbose --runInBand --bail test/unit.*test.*",
|
||||
"test-unit": "pnpm test"
|
||||
"test": "jest --env node --verbose --runInBand --bail",
|
||||
"test-unit": "pnpm test test/unit.*test.*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/error-utils": "1.0.10",
|
||||
|
||||
@@ -6,10 +6,12 @@ import { isErrnoException } from '@vercel/error-utils';
|
||||
|
||||
export class LocalFileSystemDetector extends DetectorFilesystem {
|
||||
private rootPath: string;
|
||||
|
||||
constructor(rootPath: string) {
|
||||
super();
|
||||
this.rootPath = rootPath;
|
||||
}
|
||||
|
||||
async _hasPath(name: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.stat(this.getFilePath(name));
|
||||
@@ -21,13 +23,16 @@ export class LocalFileSystemDetector extends DetectorFilesystem {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
_readFile(name: string): Promise<Buffer> {
|
||||
return fs.readFile(this.getFilePath(name));
|
||||
}
|
||||
|
||||
async _isFile(name: string): Promise<boolean> {
|
||||
const stat = await fs.stat(this.getFilePath(name));
|
||||
return stat.isFile();
|
||||
}
|
||||
|
||||
async _readdir(name: string): Promise<DetectorFilesystemStat[]> {
|
||||
const dirPath = this.getFilePath(name);
|
||||
const dir = await fs.readdir(dirPath, {
|
||||
@@ -44,14 +49,22 @@ export class LocalFileSystemDetector extends DetectorFilesystem {
|
||||
};
|
||||
return dir.map(dirent => ({
|
||||
name: dirent.name,
|
||||
path: path.join(dirPath, dirent.name),
|
||||
path: path.join(this.getRelativeFilePath(name), dirent.name),
|
||||
type: getType(dirent),
|
||||
}));
|
||||
}
|
||||
|
||||
_chdir(name: string): DetectorFilesystem {
|
||||
return new LocalFileSystemDetector(this.getFilePath(name));
|
||||
}
|
||||
|
||||
private getRelativeFilePath(name: string) {
|
||||
return name.startsWith(this.rootPath)
|
||||
? path.relative(this.rootPath, name)
|
||||
: name;
|
||||
}
|
||||
|
||||
private getFilePath(name: string) {
|
||||
return path.join(this.rootPath, name);
|
||||
return path.join(this.rootPath, this.getRelativeFilePath(name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import { LocalFileSystemDetector } from '../src';
|
||||
import { detectFramework } from '../src/detect-framework';
|
||||
import monorepoManagers from '../src/monorepos/monorepo-managers';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
|
||||
describe('monorepo-managers', () => {
|
||||
describe.each([
|
||||
@@ -17,7 +17,7 @@ describe('monorepo-managers', () => {
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
const fs = new LocalFileSystemDetector(fixture);
|
||||
|
||||
const result = await detectFramework({
|
||||
fs,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import path from 'path';
|
||||
import { packageManagers, detectFramework } from '../src';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
import {
|
||||
packageManagers,
|
||||
detectFramework,
|
||||
LocalFileSystemDetector,
|
||||
} from '../src';
|
||||
|
||||
describe('package-managers', () => {
|
||||
describe.each([
|
||||
@@ -16,7 +19,7 @@ describe('package-managers', () => {
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
const fs = new LocalFileSystemDetector(fixture);
|
||||
|
||||
const result = await detectFramework({
|
||||
fs,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import { LocalFileSystemDetector } from '../src';
|
||||
import { detectFramework } from '../src/detect-framework';
|
||||
import workspaceManagers from '../src/workspaces/workspace-managers';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
|
||||
describe('workspace-managers', () => {
|
||||
describe.each([
|
||||
@@ -19,7 +19,7 @@ describe('workspace-managers', () => {
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
const fs = new LocalFileSystemDetector(fixture);
|
||||
|
||||
const result = await detectFramework({
|
||||
fs,
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import frameworkList from '@vercel/frameworks';
|
||||
import { detectFramework } from '../src';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
import { detectFramework, LocalFileSystemDetector } from '../src';
|
||||
import { getExamples } from '../../../examples/__tests__/test-utils';
|
||||
|
||||
describe('examples should be detected', () => {
|
||||
it.each(getExamples())(
|
||||
'should detect $exampleName',
|
||||
async ({ exampleName, examplePath }) => {
|
||||
const fs = new FixtureFilesystem(examplePath);
|
||||
const fs = new LocalFileSystemDetector(examplePath);
|
||||
const framework = await detectFramework({ fs, frameworkList });
|
||||
if (!framework) {
|
||||
throw new Error(`Framework not detected for example "${exampleName}".`);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { mkdtempSync } from 'fs';
|
||||
import {
|
||||
getMonorepoDefaultSettings,
|
||||
LocalFileSystemDetector,
|
||||
MissingBuildPipeline,
|
||||
MissingBuildTarget,
|
||||
} from '../src';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
|
||||
describe('getMonorepoDefaultSettings', () => {
|
||||
test('MissingBuildTarget is an error', () => {
|
||||
@@ -69,7 +68,7 @@ describe('getMonorepoDefaultSettings', () => {
|
||||
},
|
||||
};
|
||||
|
||||
const ffs = new FixtureFilesystem(
|
||||
const fs = new LocalFileSystemDetector(
|
||||
path.join(
|
||||
__dirname,
|
||||
'fixtures',
|
||||
@@ -81,16 +80,16 @@ describe('getMonorepoDefaultSettings', () => {
|
||||
packageName,
|
||||
isRoot ? '/' : 'packages/app-1',
|
||||
isRoot ? '/' : '../..',
|
||||
ffs
|
||||
fs
|
||||
);
|
||||
expect(result).toStrictEqual(expectedResultMap[expectedResultKey]);
|
||||
}
|
||||
);
|
||||
|
||||
test('returns null when neither nx nor turbo is detected', async () => {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'monorepo-test-'));
|
||||
const lfs = new LocalFileSystemDetector(dir);
|
||||
const result = await getMonorepoDefaultSettings('', '', '', lfs);
|
||||
const dir = mkdtempSync(path.join(os.tmpdir(), 'monorepo-test-'));
|
||||
const fs = new LocalFileSystemDetector(dir);
|
||||
const result = await getMonorepoDefaultSettings('', '', '', fs);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import { normalizePath } from '@vercel/build-utils';
|
||||
import { getProjectPaths, ProjectPath } from '../src/get-project-paths';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
import { LocalFileSystemDetector } from '../src';
|
||||
|
||||
describe.each<{
|
||||
fixturePath: string;
|
||||
@@ -52,7 +52,7 @@ describe.each<{
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
const fs = new LocalFileSystemDetector(fixture);
|
||||
const mockReaddir = jest.fn().mockImplementation(fs.readdir);
|
||||
const mockHasPath = jest.fn().mockImplementation(fs.hasPath);
|
||||
fs.readdir = mockReaddir;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import { getWorkspaces } from '../src/workspaces/get-workspaces';
|
||||
import { getWorkspacePackagePaths } from '../src/workspaces/get-workspace-package-paths';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
import { LocalFileSystemDetector } from '../src';
|
||||
|
||||
describe.each<[string, string[]]>([
|
||||
['21-npm-workspaces', ['/a', '/b']],
|
||||
@@ -32,7 +32,7 @@ describe.each<[string, string[]]>([
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
const fs = new LocalFileSystemDetector(fixture);
|
||||
|
||||
const workspaces = await getWorkspaces({ fs });
|
||||
const actualPackagePaths = (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path';
|
||||
import { LocalFileSystemDetector } from '../src';
|
||||
import { getWorkspaces, Workspace } from '../src/workspaces/get-workspaces';
|
||||
import { FixtureFilesystem } from './utils/fixture-filesystem';
|
||||
|
||||
describe.each<[string, Workspace[]]>([
|
||||
['21-npm-workspaces', [{ type: 'npm', rootPath: '/' }]],
|
||||
@@ -34,7 +34,7 @@ describe.each<[string, Workspace[]]>([
|
||||
|
||||
it(testName, async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', fixturePath);
|
||||
const fs = new FixtureFilesystem(fixture);
|
||||
const fs = new LocalFileSystemDetector(fixture);
|
||||
|
||||
const actualWorkspaces = await getWorkspaces({ fs });
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { LocalFileSystemDetector, DetectorFilesystem } from '../src';
|
||||
|
||||
const tmpdir = path.join(os.tmpdir(), 'local-file-system-test');
|
||||
|
||||
const dirs = ['', 'a', 'a/b']; // root, single-nested, double-nested
|
||||
const dirs = ['', 'a', `a${path.sep}b`]; // root, single-nested, double-nested
|
||||
const files = ['foo', 'bar'];
|
||||
const filePaths = dirs.flatMap(dir => files.map(file => path.join(dir, file)));
|
||||
|
||||
@@ -63,12 +63,7 @@ describe('LocalFileSystemDetector', () => {
|
||||
const readdirResults = await Promise.all(
|
||||
dirs.map(dir => localFileSystem.readdir(dir))
|
||||
);
|
||||
const expectedPaths = [
|
||||
...dirs.map(dir => path.join(tmpdir, dir)),
|
||||
...filePaths.map(filePath => path.join(tmpdir, filePath)),
|
||||
]
|
||||
.sort()
|
||||
.slice(1); // drop the first path since its the root
|
||||
const expectedPaths = [...dirs, ...filePaths].sort().slice(1); // drop the first path since its the root
|
||||
const actualPaths = readdirResults
|
||||
.flatMap(result => result.map(stat => stat.path))
|
||||
.sort();
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { promises } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { DetectorFilesystem } from '../../src';
|
||||
import { DetectorFilesystemStat } from '../../src/detectors/filesystem';
|
||||
|
||||
const { stat, readFile, readdir } = promises;
|
||||
|
||||
export class FixtureFilesystem extends DetectorFilesystem {
|
||||
private rootPath: string;
|
||||
|
||||
constructor(fixturePath: string) {
|
||||
super();
|
||||
|
||||
this.rootPath = fixturePath;
|
||||
}
|
||||
|
||||
async _hasPath(name: string): Promise<boolean> {
|
||||
try {
|
||||
const filePath = path.join(this.rootPath, name);
|
||||
await stat(filePath);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async _readFile(name: string): Promise<Buffer> {
|
||||
const filePath = path.join(this.rootPath, name);
|
||||
return readFile(filePath);
|
||||
}
|
||||
async _isFile(name: string): Promise<boolean> {
|
||||
const filePath = path.join(this.rootPath, name);
|
||||
return (await stat(filePath)).isFile();
|
||||
}
|
||||
|
||||
async _readdir(name: string): Promise<DetectorFilesystemStat[]> {
|
||||
const dirPath = path.join(this.rootPath, name);
|
||||
const files = await readdir(dirPath, { withFileTypes: true });
|
||||
|
||||
return files.map(file => ({
|
||||
name: file.name,
|
||||
type: file.isFile() ? 'file' : 'dir',
|
||||
path: path.join(name, file.name),
|
||||
}));
|
||||
}
|
||||
|
||||
_chdir(name: string): DetectorFilesystem {
|
||||
return new FixtureFilesystem(path.join(this.rootPath, name));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user