mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
feat: Add support for linking explicit files in addition to directories
Co-authored-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
parent
d61deb8b73
commit
fb6bf2143c
@ -0,0 +1,14 @@
|
|||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import fse from "fs-extra";
|
||||||
|
|
||||||
|
export type IsFileOrDirectory = (path: string) => Promise<"file" | "dir">;
|
||||||
|
|
||||||
|
export const isFileOrDirectoryInjectable = getInjectable({
|
||||||
|
id: "is-file-or-directory",
|
||||||
|
|
||||||
|
instantiate: (): IsFileOrDirectory => async (path: string) => {
|
||||||
|
const stat = await fse.stat(path);
|
||||||
|
|
||||||
|
return stat.isDirectory() ? "dir" : "file";
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -7,6 +7,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import { pipeline } from "@ogre-tools/fp";
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { getLensLinkDirectoryInjectable } from "./get-lens-link-directory.injectable";
|
import { getLensLinkDirectoryInjectable } from "./get-lens-link-directory.injectable";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { isFileOrDirectoryInjectable } from "./fs/is-file-or-directory.injectable";
|
||||||
|
|
||||||
const shouldBeGlobbed = (possibleGlobString: string) => possibleGlobString.includes("*");
|
const shouldBeGlobbed = (possibleGlobString: string) => possibleGlobString.includes("*");
|
||||||
const simplifyGlobbing = new RegExp("(\\/\\*\\/\\*\\*|\\/\\*\\*|\\/\\*\\*\\/\\*|\\/\\*)$");
|
const simplifyGlobbing = new RegExp("(\\/\\*\\/\\*\\*|\\/\\*\\*|\\/\\*\\*\\/\\*|\\/\\*)$");
|
||||||
@ -19,6 +20,7 @@ export const getSymlinkPathsInjectable = getInjectable({
|
|||||||
const glob = di.inject(globInjectable);
|
const glob = di.inject(globInjectable);
|
||||||
const resolvePath = di.inject(resolvePathInjectable);
|
const resolvePath = di.inject(resolvePathInjectable);
|
||||||
const getLensLinkDirectory = di.inject(getLensLinkDirectoryInjectable);
|
const getLensLinkDirectory = di.inject(getLensLinkDirectoryInjectable);
|
||||||
|
const isFileOrDirectory = di.inject(isFileOrDirectoryInjectable);
|
||||||
|
|
||||||
return async (packageJsons: PackageJsonAndPath[]) => {
|
return async (packageJsons: PackageJsonAndPath[]) => {
|
||||||
return pipeline(
|
return pipeline(
|
||||||
@ -39,6 +41,22 @@ export const getSymlinkPathsInjectable = getInjectable({
|
|||||||
globbeds = await glob(toBeGlobbed, { cwd: moduleDirectory });
|
globbeds = await glob(toBeGlobbed, { cwd: moduleDirectory });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const notGlobbedFilesOrDirectories = await pipeline(
|
||||||
|
toNotBeGlobbed,
|
||||||
|
|
||||||
|
map(async (fileOrDirectory) => {
|
||||||
|
const target = resolvePath(moduleDirectory, fileOrDirectory);
|
||||||
|
|
||||||
|
return {
|
||||||
|
target,
|
||||||
|
source: resolvePath(lensLinkDirectory, fileOrDirectory),
|
||||||
|
type: await isFileOrDirectory(target),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
awaitAll,
|
||||||
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
target: packageJsonPath,
|
target: packageJsonPath,
|
||||||
@ -52,11 +70,7 @@ export const getSymlinkPathsInjectable = getInjectable({
|
|||||||
type: "file" as const,
|
type: "file" as const,
|
||||||
})),
|
})),
|
||||||
|
|
||||||
...toNotBeGlobbed.map((fileOrDirectory) => ({
|
...notGlobbedFilesOrDirectories,
|
||||||
target: resolvePath(moduleDirectory, fileOrDirectory),
|
|
||||||
source: resolvePath(lensLinkDirectory, fileOrDirectory),
|
|
||||||
type: "dir" as const,
|
|
||||||
})),
|
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import { removeDirectoryInjectable } from "./fs/remove-directory.injectable";
|
|||||||
import { getDi } from "./get-di";
|
import { getDi } from "./get-di";
|
||||||
import type { Glob } from "./fs/glob.injectable";
|
import type { Glob } from "./fs/glob.injectable";
|
||||||
import { globInjectable } from "./fs/glob.injectable";
|
import { globInjectable } from "./fs/glob.injectable";
|
||||||
|
import type { IsFileOrDirectory } from "./fs/is-file-or-directory.injectable";
|
||||||
|
import { isFileOrDirectoryInjectable } from "./fs/is-file-or-directory.injectable";
|
||||||
|
|
||||||
describe("lens-link", () => {
|
describe("lens-link", () => {
|
||||||
let lensLink: LensLink;
|
let lensLink: LensLink;
|
||||||
@ -31,6 +33,7 @@ describe("lens-link", () => {
|
|||||||
let ensureDirectoryMock: AsyncFnMock<EnsureDirectory>;
|
let ensureDirectoryMock: AsyncFnMock<EnsureDirectory>;
|
||||||
let removeDirectoryMock: AsyncFnMock<RemoveDirectory>;
|
let removeDirectoryMock: AsyncFnMock<RemoveDirectory>;
|
||||||
let globMock: AsyncFnMock<Glob>;
|
let globMock: AsyncFnMock<Glob>;
|
||||||
|
let isFileOrDirectoryMock: AsyncFnMock<IsFileOrDirectory>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
existsMock = asyncFn();
|
existsMock = asyncFn();
|
||||||
@ -39,6 +42,7 @@ describe("lens-link", () => {
|
|||||||
createSymlinkMock = asyncFn();
|
createSymlinkMock = asyncFn();
|
||||||
ensureDirectoryMock = asyncFn();
|
ensureDirectoryMock = asyncFn();
|
||||||
removeDirectoryMock = asyncFn();
|
removeDirectoryMock = asyncFn();
|
||||||
|
isFileOrDirectoryMock = asyncFn();
|
||||||
globMock = asyncFn();
|
globMock = asyncFn();
|
||||||
|
|
||||||
const di = getDi();
|
const di = getDi();
|
||||||
@ -52,6 +56,7 @@ describe("lens-link", () => {
|
|||||||
di.override(ensureDirectoryInjectable, () => ensureDirectoryMock);
|
di.override(ensureDirectoryInjectable, () => ensureDirectoryMock);
|
||||||
di.override(removeDirectoryInjectable, () => removeDirectoryMock);
|
di.override(removeDirectoryInjectable, () => removeDirectoryMock);
|
||||||
di.override(globInjectable, () => globMock);
|
di.override(globInjectable, () => globMock);
|
||||||
|
di.override(isFileOrDirectoryInjectable, () => isFileOrDirectoryMock);
|
||||||
|
|
||||||
lensLink = di.inject(lensLinkInjectable);
|
lensLink = di.inject(lensLinkInjectable);
|
||||||
});
|
});
|
||||||
@ -235,10 +240,13 @@ describe("lens-link", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when creation of Lens link directories resolve", () => {
|
describe("when creation of Lens link directories and files or directories are identified is resolve", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await ensureDirectoryMock.resolve();
|
await ensureDirectoryMock.resolve();
|
||||||
await ensureDirectoryMock.resolve();
|
await ensureDirectoryMock.resolve();
|
||||||
|
|
||||||
|
await isFileOrDirectoryMock.resolve("dir");
|
||||||
|
await isFileOrDirectoryMock.resolve("dir");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates the symlinks to scoped directories", () => {
|
it("creates the symlinks to scoped directories", () => {
|
||||||
@ -327,9 +335,13 @@ describe("lens-link", () => {
|
|||||||
expect(createSymlinkMock).not.toHaveBeenCalled();
|
expect(createSymlinkMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when globbing resolves", () => {
|
describe("when globbing resolves and files or directories are identified", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await globMock.resolve(["/some-directory/some-module/some-file-from-glob.txt"]);
|
await globMock.resolve(["/some-directory/some-module/some-file-from-glob.txt"]);
|
||||||
|
|
||||||
|
await isFileOrDirectoryMock.resolve("dir");
|
||||||
|
await isFileOrDirectoryMock.resolve("dir");
|
||||||
|
await isFileOrDirectoryMock.resolve("dir");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates the symlinks to files and directories that were both globbed and that avoided globbing", () => {
|
it("creates the symlinks to files and directories that were both globbed and that avoided globbing", () => {
|
||||||
@ -381,7 +393,7 @@ describe("lens-link", () => {
|
|||||||
|
|
||||||
await readJsonFileMock.resolveSpecific(([path]) => path === "/some-directory/some-module/package.json", {
|
await readJsonFileMock.resolveSpecific(([path]) => path === "/some-directory/some-module/package.json", {
|
||||||
name: "some-module",
|
name: "some-module",
|
||||||
files: ["some-build-directory"],
|
files: ["some-build-directory", "some-file"],
|
||||||
main: "some-build-directory/index.js",
|
main: "some-build-directory/index.js",
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -439,7 +451,7 @@ describe("lens-link", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("given Lens link directories does not exist", () => {
|
describe("given Lens link directories do not exist", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await existsMock.resolve(false);
|
await existsMock.resolve(false);
|
||||||
await existsMock.resolve(false);
|
await existsMock.resolve(false);
|
||||||
@ -462,50 +474,89 @@ describe("lens-link", () => {
|
|||||||
await ensureDirectoryMock.resolve();
|
await ensureDirectoryMock.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates the symlinks", () => {
|
it("doesn't create symlinks yet", () => {
|
||||||
expect(createSymlinkMock.mock.calls).toEqual([
|
expect(createSymlinkMock).not.toHaveBeenCalled();
|
||||||
[
|
});
|
||||||
"/some-directory/some-module/package.json",
|
|
||||||
"/some-directory/some-project/node_modules/some-module/package.json",
|
it("calls for if symlinks to be created are for files or directories", () => {
|
||||||
"file",
|
expect(isFileOrDirectoryMock.mock.calls).toEqual([
|
||||||
],
|
["/some-directory/some-module/some-build-directory"],
|
||||||
[
|
["/some-directory/some-module/some-file"],
|
||||||
"/some-directory/some-module/some-build-directory",
|
["/some-other-directory/some-other-module/some-other-build-directory"],
|
||||||
"/some-directory/some-project/node_modules/some-module/some-build-directory",
|
|
||||||
"dir",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"/some-other-directory/some-other-module/package.json",
|
|
||||||
"/some-directory/some-project/node_modules/some-other-module/package.json",
|
|
||||||
"file",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"/some-other-directory/some-other-module/some-other-build-directory",
|
|
||||||
"/some-directory/some-project/node_modules/some-other-module/some-other-build-directory",
|
|
||||||
"dir",
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("given all symlink creations have not resolved, does not resolve yet", async () => {
|
describe("given calls for files or directories resolve", () => {
|
||||||
createSymlinkMock.resolve();
|
beforeEach(async () => {
|
||||||
createSymlinkMock.resolve();
|
await isFileOrDirectoryMock.resolveSpecific(
|
||||||
createSymlinkMock.resolve();
|
["/some-directory/some-module/some-build-directory"],
|
||||||
|
"dir",
|
||||||
|
);
|
||||||
|
|
||||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
await isFileOrDirectoryMock.resolveSpecific(["/some-directory/some-module/some-file"], "file");
|
||||||
|
|
||||||
expect(promiseStatus.fulfilled).toBe(false);
|
await isFileOrDirectoryMock.resolveSpecific(
|
||||||
});
|
["/some-other-directory/some-other-module/some-other-build-directory"],
|
||||||
|
"dir",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("when symlink creations resolve, ends script", async () => {
|
it("creates the symlinks", () => {
|
||||||
createSymlinkMock.resolve();
|
expect(createSymlinkMock.mock.calls).toEqual([
|
||||||
createSymlinkMock.resolve();
|
[
|
||||||
createSymlinkMock.resolve();
|
"/some-directory/some-module/package.json",
|
||||||
createSymlinkMock.resolve();
|
"/some-directory/some-project/node_modules/some-module/package.json",
|
||||||
|
"file",
|
||||||
|
],
|
||||||
|
|
||||||
const promiseStatus = await getPromiseStatus(actualPromise);
|
[
|
||||||
|
"/some-directory/some-module/some-build-directory",
|
||||||
|
"/some-directory/some-project/node_modules/some-module/some-build-directory",
|
||||||
|
"dir",
|
||||||
|
],
|
||||||
|
|
||||||
expect(promiseStatus.fulfilled).toBe(true);
|
[
|
||||||
|
"/some-directory/some-module/some-file",
|
||||||
|
"/some-directory/some-project/node_modules/some-module/some-file",
|
||||||
|
"file",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-other-directory/some-other-module/package.json",
|
||||||
|
"/some-directory/some-project/node_modules/some-other-module/package.json",
|
||||||
|
"file",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"/some-other-directory/some-other-module/some-other-build-directory",
|
||||||
|
"/some-directory/some-project/node_modules/some-other-module/some-other-build-directory",
|
||||||
|
"dir",
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("given all symlink creations have not resolved, does not resolve yet", async () => {
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
|
||||||
|
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||||
|
|
||||||
|
expect(promiseStatus.fulfilled).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when symlink creations resolve, ends script", async () => {
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
createSymlinkMock.resolve();
|
||||||
|
|
||||||
|
const promiseStatus = await getPromiseStatus(actualPromise);
|
||||||
|
|
||||||
|
expect(promiseStatus.fulfilled).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user