Skip to content

Commit

Permalink
fix(config-tools): Added more accurate search for workspace root
Browse files Browse the repository at this point in the history
  • Loading branch information
sullivanpj committed Dec 20, 2023
1 parent 88f4feb commit c418b08
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 13 deletions.
2 changes: 1 addition & 1 deletion packages/config-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This package is part of the <b>⚡Storm-Ops</b> monorepo. The Storm-Ops packages

<h3 align="center">💻 Visit <a href="https://stormsoftware.org" target="_blank">stormsoftware.org</a> to stay up to date with this developer</h3><br />

[![Version](https://img.shields.io/badge/version-1.5.3-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Version](https://img.shields.io/badge/version-1.5.6-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Nx](https://img.shields.io/badge/Nx-17.0.2-lightgrey?style=for-the-badge&logo=nx&logoWidth=20&&color=1fb2a6)](http://nx.dev/)&nbsp;[![NextJs](https://img.shields.io/badge/Next.js-14.0.2-lightgrey?style=for-the-badge&logo=nextdotjs&logoWidth=20&color=1fb2a6)](https://nextjs.org/)&nbsp;[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=for-the-badge&logo=commitlint&color=1fb2a6)](http://commitizen.github.io/cz-cli/)&nbsp;![Semantic-Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge&color=1fb2a6)&nbsp;[![documented with docusaurus](https://img.shields.io/badge/documented_with-docusaurus-success.svg?style=for-the-badge&logo=readthedocs&color=1fb2a6)](https://docusaurus.io/)&nbsp;![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/storm-software/storm-ops/cr.yml?style=for-the-badge&logo=github-actions&color=1fb2a6)

<h3 align="center" bold="true">⚠️ <b>Attention</b> ⚠️ This repository, and the apps, libraries, and tools contained within, is still in it's initial development phase. As a result, bugs and issues are expected with it's usage. When the main development phase completes, a proper release will be performed, the packages will be availible through NPM (and other distributions), and this message will be removed. However, in the meantime, please feel free to report any issues you may come across.</h3><br />
Expand Down
3 changes: 3 additions & 0 deletions packages/config-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"types": "declarations.d.ts",
"dependencies": {
"cosmiconfig": "^9.0.0",
"find-up": "^7.0.0",
"fp-ts": "^2.16.1",
"locate-path": "^7.2.0",
"zod": "^3.22.4"
},
"publishConfig": {
Expand Down
3 changes: 3 additions & 0 deletions packages/config-tools/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"outputs": ["{options.outputPath}"],
"options": {
"main": "packages/config-tools/src/index.ts",
"additionalEntryPoints": [
"packages/config-tools/src/utilities/find-workspace-root.ts"
],
"outputPath": "dist/packages/config-tools",
"tsConfig": "packages/config-tools/tsconfig.json",
"project": "packages/config-tools/package.json",
Expand Down
167 changes: 167 additions & 0 deletions packages/config-tools/src/utilities/find-up.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { locatePath, locatePathSync } from "locate-path";
import path from "path";
import { fileURLToPath } from "url";

export interface FindUpOptions {
cwd?: string;
type: "file" | "directory";
stopAt?: string;
limit: number;
}

export const findUpStop = Symbol("findUpStop");

function toPath(urlOrPath) {
return urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
}

export async function findUpMultiple(
names:
| string
| string[]
| ((cwd: string) => string)
| ((cwd: string) => string)[],
options: FindUpOptions = { limit: Number.POSITIVE_INFINITY, type: "file" }
) {
let directory = path.resolve(toPath(options.cwd) ?? "");
const { root } = path.parse(directory);
const stopAt = path.resolve(directory, toPath(options.stopAt ?? root));
const limit = options.limit ?? Number.POSITIVE_INFINITY;

if (typeof names === "function") {
const foundPath = names(options.cwd);

return locatePathSync([foundPath], { ...options, cwd: directory });
}

const runNameMatcher = async (name: string | ((cwd: string) => string)) => {
const paths = [name].flat();

const runMatcher = async locateOptions => {
if (typeof name !== "function") {
return locatePath(paths as string[], locateOptions);
}

const foundPath = await name(locateOptions.cwd);
if (typeof foundPath === "string") {
return locatePath([foundPath], locateOptions);
}

return foundPath;
};

const matches = [];
// eslint-disable-next-line no-constant-condition
while (true) {
// eslint-disable-next-line no-await-in-loop
const foundPath = await runMatcher({ ...options, cwd: directory });
if (foundPath) {
matches.push(path.resolve(directory, foundPath));
}

if (directory === stopAt || matches.length >= limit) {
break;
}

directory = path.dirname(directory);
}

return matches;
};

return (
await Promise.allSettled(
(
(names && Array.isArray(names) ? names : [names]) as
| string[]
| ((cwd: string) => string)[]
).map((name: string | ((cwd: string) => string)) => runNameMatcher(name))
)
).flat();
}

export function findUpMultipleSync(
names:
| string
| string[]
| ((cwd: string) => string)
| ((cwd: string) => string)[],
options: FindUpOptions = { limit: 1, type: "file" }
) {
let directory = path.resolve(toPath(options.cwd) ?? "");
const { root } = path.parse(directory);
const stopAt = path.resolve(directory, toPath(options.stopAt) ?? root);
const limit = options.limit ?? Number.POSITIVE_INFINITY;

if (typeof names === "function") {
const foundPath = names(options.cwd);

return locatePathSync([foundPath], options);
}

const runNameMatcher = (name: string | ((cwd: string) => string)) => {
const paths = [name].flat();

const runMatcher = locateOptions => {
if (typeof name !== "function") {
return locatePathSync(paths as string[], locateOptions);
}

const foundPath = name(locateOptions.cwd);
if (typeof foundPath === "string") {
return locatePathSync([foundPath], locateOptions);
}

return foundPath;
};

const matches = [];
// eslint-disable-next-line no-constant-condition
while (true) {
const foundPath = runMatcher({ ...options, cwd: directory });
if (foundPath) {
matches.push(path.resolve(directory, foundPath));
}

if (directory === stopAt || matches.length >= limit) {
break;
}

directory = path.dirname(directory);
}

return matches;
};

return (
(names && Array.isArray(names) ? names : [names]) as
| string[]
| ((cwd: string) => string)[]
)
.map((name: string | ((cwd: string) => string)) => runNameMatcher(name))
.flat();
}

export async function findUp(
names:
| string
| string[]
| ((cwd: string) => string)
| ((cwd: string) => string)[],
options: FindUpOptions = { limit: 1, type: "file" }
) {
const matches = await findUpMultiple(names, options);
return matches[0];
}

export function findUpSync(
names:
| string
| string[]
| ((cwd: string) => string)
| ((cwd: string) => string)[],
options: FindUpOptions = { limit: 1, type: "file" }
) {
const matches = findUpMultipleSync(names, options);
return matches[0];
}
82 changes: 82 additions & 0 deletions packages/config-tools/src/utilities/find-workspace-root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* monorepo-root
* Find the monorepo root directory
*/

import * as path from "path";

import { Either, alt, chain, fromNullable, map, mapLeft } from "fp-ts/Either";
import { constant, pipe } from "fp-ts/function";
import { findUp } from "./find-up";

export type WorkspaceRootError = {
type: string;
path: string;
};

const rootFiles = [
"lerna.json",
"nx.json",
"turbo.json",
"npm-workspace.json",
"yarn-workspace.json",
"pnpm-workspace.json",
"npm-workspace.yaml",
"yarn-workspace.yaml",
"pnpm-workspace.yaml",
"npm-workspace.yml",
"yarn-workspace.yml",
"pnpm-workspace.yml",
"npm-lock.json",
"yarn-lock.json",
"pnpm-lock.json",
"npm-lock.yaml",
"yarn-lock.yaml",
"pnpm-lock.yaml",
"npm-lock.yml",
"yarn-lock.yml",
"pnpm-lock.yml",
"bun.lockb"
];

const formatError = (path: string): WorkspaceRootError => ({
type: `Cannot find workspace root upwards from known path. Files search list includes: \n${rootFiles.join(
"\n"
)}`,
path
});

const searchUp = (
target: string[],
cwd: string
): Either<WorkspaceRootError, string> =>
pipe(
// FIXME: this should be async, or at least offer an async version in addition
findUp(target, {
cwd,
type: "file",
limit: 1
}),
fromNullable(formatError(cwd)),
map(path.dirname as any)
);

/**
* Find the monorepo root directory, searching upwards from `path`.
*/
export function findWorkspaceRoot(pathInsideMonorepo?: string) {
return process.env.STORM_WORKSPACE_ROOT
? process.env.STORM_WORKSPACE_ROOT
: process.env.NX_WORKSPACE_ROOT_PATH
? process.env.NX_WORKSPACE_ROOT_PATH
: pipe(
fromNullable(formatError(""))(pathInsideMonorepo),
chain(from => searchUp(rootFiles, from)),
alt(() =>
pipe(
searchUp(rootFiles, process.cwd()),
mapLeft(constant(formatError(process.cwd())))
)
)
);
}
14 changes: 5 additions & 9 deletions packages/config-tools/src/utilities/get-default-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ export const getDefaultConfig = (
let license = DefaultStormConfig.license;
let homepage = DefaultStormConfig.homepage;

const workspaceRoot = getWorkspaceRoot() ?? process.cwd();
const workspaceRoot = findWorkspaceRoot(process.cwd());
if (typeof workspaceRoot !== "string") {
throw new Error("Could not find workspace root");
}

if (existsSync(join(workspaceRoot, "package.json"))) {
const file = readFileSync(join(workspaceRoot, "package.json"), {
encoding: "utf-8"
Expand Down Expand Up @@ -85,11 +89,3 @@ export const getDefaultConfig = (
})
) as StormConfig;
};

const getWorkspaceRoot = () => {
const root = findWorkspaceRoot(process.cwd());
process.env.STORM_WORKSPACE_ROOT ??= root?.dir;
process.env.NX_WORKSPACE_ROOT_PATH ??= root?.dir;

return root?.dir;
};
1 change: 1 addition & 0 deletions packages/config-tools/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"allowSyntheticDefaultImports": true,
"noEmit": true
},
"files": [],
Expand Down
2 changes: 1 addition & 1 deletion packages/create-storm-workspace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This package is part of the <b>⚡Storm-Ops</b> monorepo. The Storm-Ops packages

<h3 align="center">💻 Visit <a href="https://stormsoftware.org" target="_blank">stormsoftware.org</a> to stay up to date with this developer</h3><br />

[![Version](https://img.shields.io/badge/version-1.31.6-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Version](https://img.shields.io/badge/version-1.31.9-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Nx](https://img.shields.io/badge/Nx-17.0.2-lightgrey?style=for-the-badge&logo=nx&logoWidth=20&&color=1fb2a6)](http://nx.dev/)&nbsp;[![NextJs](https://img.shields.io/badge/Next.js-14.0.2-lightgrey?style=for-the-badge&logo=nextdotjs&logoWidth=20&color=1fb2a6)](https://nextjs.org/)&nbsp;[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=for-the-badge&logo=commitlint&color=1fb2a6)](http://commitizen.github.io/cz-cli/)&nbsp;![Semantic-Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge&color=1fb2a6)&nbsp;[![documented with docusaurus](https://img.shields.io/badge/documented_with-docusaurus-success.svg?style=for-the-badge&logo=readthedocs&color=1fb2a6)](https://docusaurus.io/)&nbsp;![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/storm-software/storm-ops/cr.yml?style=for-the-badge&logo=github-actions&color=1fb2a6)

<h3 align="center" bold="true">⚠️ <b>Attention</b> ⚠️ This repository, and the apps, libraries, and tools contained within, is still in it's initial development phase. As a result, bugs and issues are expected with it's usage. When the main development phase completes, a proper release will be performed, the packages will be availible through NPM (and other distributions), and this message will be removed. However, in the meantime, please feel free to report any issues you may come across.</h3><br />
Expand Down
2 changes: 1 addition & 1 deletion packages/git-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This package is part of the <b>⚡Storm-Ops</b> monorepo. The Storm-Ops packages

<h3 align="center">💻 Visit <a href="https://stormsoftware.org" target="_blank">stormsoftware.org</a> to stay up to date with this developer</h3><br />

[![Version](https://img.shields.io/badge/version-1.17.1-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Version](https://img.shields.io/badge/version-1.17.2-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Nx](https://img.shields.io/badge/Nx-17.0.2-lightgrey?style=for-the-badge&logo=nx&logoWidth=20&&color=1fb2a6)](http://nx.dev/)&nbsp;[![NextJs](https://img.shields.io/badge/Next.js-14.0.2-lightgrey?style=for-the-badge&logo=nextdotjs&logoWidth=20&color=1fb2a6)](https://nextjs.org/)&nbsp;[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=for-the-badge&logo=commitlint&color=1fb2a6)](http://commitizen.github.io/cz-cli/)&nbsp;![Semantic-Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge&color=1fb2a6)&nbsp;[![documented with docusaurus](https://img.shields.io/badge/documented_with-docusaurus-success.svg?style=for-the-badge&logo=readthedocs&color=1fb2a6)](https://docusaurus.io/)&nbsp;![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/storm-software/storm-ops/cr.yml?style=for-the-badge&logo=github-actions&color=1fb2a6)

<h3 align="center" bold="true">⚠️ <b>Attention</b> ⚠️ This repository, and the apps, libraries, and tools contained within, is still in it's initial development phase. As a result, bugs and issues are expected with it's usage. When the main development phase completes, a proper release will be performed, the packages will be availible through NPM (and other distributions), and this message will be removed. However, in the meantime, please feel free to report any issues you may come across.</h3><br />
Expand Down
2 changes: 1 addition & 1 deletion packages/workspace-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This package is part of the <b>⚡Storm-Ops</b> monorepo. The Storm-Ops packages

<h3 align="center">💻 Visit <a href="https://stormsoftware.org" target="_blank">stormsoftware.org</a> to stay up to date with this developer</h3><br />

[![Version](https://img.shields.io/badge/version-1.31.6-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Version](https://img.shields.io/badge/version-1.31.9-1fb2a6.svg?style=for-the-badge&color=1fb2a6)](https://prettier.io/)&nbsp;
[![Nx](https://img.shields.io/badge/Nx-17.0.2-lightgrey?style=for-the-badge&logo=nx&logoWidth=20&&color=1fb2a6)](http://nx.dev/)&nbsp;[![NextJs](https://img.shields.io/badge/Next.js-14.0.2-lightgrey?style=for-the-badge&logo=nextdotjs&logoWidth=20&color=1fb2a6)](https://nextjs.org/)&nbsp;[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=for-the-badge&logo=commitlint&color=1fb2a6)](http://commitizen.github.io/cz-cli/)&nbsp;![Semantic-Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=for-the-badge&color=1fb2a6)&nbsp;[![documented with docusaurus](https://img.shields.io/badge/documented_with-docusaurus-success.svg?style=for-the-badge&logo=readthedocs&color=1fb2a6)](https://docusaurus.io/)&nbsp;![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/storm-software/storm-ops/cr.yml?style=for-the-badge&logo=github-actions&color=1fb2a6)

<h3 align="center" bold="true">⚠️ <b>Attention</b> ⚠️ This repository, and the apps, libraries, and tools contained within, is still in it's initial development phase. As a result, bugs and issues are expected with it's usage. When the main development phase completes, a proper release will be performed, the packages will be availible through NPM (and other distributions), and this message will be removed. However, in the meantime, please feel free to report any issues you may come across.</h3><br />
Expand Down
28 changes: 28 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c418b08

Please sign in to comment.