diff options
| author | 2023-04-28 01:36:44 +0800 | |
|---|---|---|
| committer | 2023-04-28 01:36:44 +0800 | |
| commit | dd84b9d64fb98746a230cd24233ff50a562c39c9 (patch) | |
| tree | b583261ef00b3afe72ec4d6dacb31e57779a6faf /packages/turbo-workspaces/src/utils.ts | |
| parent | 0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff) | |
| download | HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip | |
Diffstat (limited to 'packages/turbo-workspaces/src/utils.ts')
| -rw-r--r-- | packages/turbo-workspaces/src/utils.ts | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/packages/turbo-workspaces/src/utils.ts b/packages/turbo-workspaces/src/utils.ts new file mode 100644 index 0000000..8290203 --- /dev/null +++ b/packages/turbo-workspaces/src/utils.ts @@ -0,0 +1,197 @@ +import fs from "fs-extra"; +import path from "path"; +import glob from "fast-glob"; +import yaml from "js-yaml"; +import { + PackageJson, + PackageManager, + Project, + Workspace, + WorkspaceInfo, +} from "./types"; +import { ConvertError } from "./errors"; + +// adapted from https://github.com/nodejs/corepack/blob/cae770694e62f15fed33dd8023649d77d96023c1/sources/specUtils.ts#L14 +const PACKAGE_MANAGER_REGEX = /^(?!_)(.+)@(.+)$/; + +function getPackageJson({ + workspaceRoot, +}: { + workspaceRoot: string; +}): PackageJson { + const packageJsonPath = path.join(workspaceRoot, "package.json"); + try { + return fs.readJsonSync(packageJsonPath, "utf8"); + } catch (err) { + if (err && typeof err === "object" && "code" in err) { + if (err.code === "ENOENT") { + throw new ConvertError(`no "package.json" found at ${workspaceRoot}`, { + type: "package_json-missing", + }); + } + if (err.code === "EJSONPARSE") { + throw new ConvertError( + `failed to parse "package.json" at ${workspaceRoot}`, + { + type: "package_json-parse_error", + } + ); + } + } + throw new Error( + `unexpected error reading "package.json" at ${workspaceRoot}` + ); + } +} + +function getWorkspacePackageManager({ + workspaceRoot, +}: { + workspaceRoot: string; +}): string | undefined { + const { packageManager } = getPackageJson({ workspaceRoot }); + if (packageManager) { + try { + const match = packageManager.match(PACKAGE_MANAGER_REGEX); + if (match) { + const [_, manager] = match; + return manager; + } + } catch (err) { + // this won't always exist. + } + } + return undefined; +} + +function getWorkspaceInfo({ + workspaceRoot, +}: { + workspaceRoot: string; +}): WorkspaceInfo { + const packageJson = getPackageJson({ workspaceRoot }); + const workspaceDirectory = path.basename(workspaceRoot); + + const { name = workspaceDirectory, description } = packageJson; + + return { + name, + description, + }; +} + +function getPnpmWorkspaces({ + workspaceRoot, +}: { + workspaceRoot: string; +}): Array<string> { + const workspaceFile = path.join(workspaceRoot, "pnpm-workspace.yaml"); + if (fs.existsSync(workspaceFile)) { + try { + const workspaceConfig = yaml.load(fs.readFileSync(workspaceFile, "utf8")); + // validate it's the type we expect + if ( + workspaceConfig instanceof Object && + "packages" in workspaceConfig && + Array.isArray(workspaceConfig.packages) + ) { + return workspaceConfig.packages as Array<string>; + } + } catch (err) { + throw new ConvertError(`failed to parse ${workspaceFile}`, { + type: "pnpm-workspace_parse_error", + }); + } + } + + return []; +} + +function expandPaths({ + root, + lockFile, + workspaceConfig, +}: { + root: string; + lockFile: string; + workspaceConfig?: string; +}) { + const fromRoot = (p: string) => path.join(root, p); + const paths: Project["paths"] = { + root, + lockfile: fromRoot(lockFile), + packageJson: fromRoot("package.json"), + nodeModules: fromRoot("node_modules"), + }; + + if (workspaceConfig) { + paths.workspaceConfig = fromRoot(workspaceConfig); + } + + return paths; +} + +function expandWorkspaces({ + workspaceRoot, + workspaceGlobs, +}: { + workspaceRoot: string; + workspaceGlobs?: string[]; +}): Array<Workspace> { + if (!workspaceGlobs) { + return []; + } + return workspaceGlobs + .flatMap((workspaceGlob) => { + const workspacePackageJsonGlob = `${workspaceGlob}/package.json`; + return glob.sync(workspacePackageJsonGlob, { + onlyFiles: true, + absolute: true, + cwd: workspaceRoot, + }); + }) + .map((workspacePackageJson) => { + const workspaceRoot = path.dirname(workspacePackageJson); + const { name, description } = getWorkspaceInfo({ workspaceRoot }); + return { + name, + description, + paths: { + root: workspaceRoot, + packageJson: workspacePackageJson, + nodeModules: path.join(workspaceRoot, "node_modules"), + }, + }; + }); +} + +function directoryInfo({ directory }: { directory: string }) { + const dir = path.resolve(process.cwd(), directory); + return { exists: fs.existsSync(dir), absolute: dir }; +} + +function getMainStep({ + packageManager, + action, + project, +}: { + packageManager: PackageManager; + action: "create" | "remove"; + project: Project; +}) { + const hasWorkspaces = project.workspaceData.globs.length > 0; + return `${action === "remove" ? "Removing" : "Adding"} ${packageManager} ${ + hasWorkspaces ? "workspaces" : "" + } ${action === "remove" ? "from" : "to"} ${project.name}`; +} + +export { + getPackageJson, + getWorkspacePackageManager, + getWorkspaceInfo, + expandPaths, + expandWorkspaces, + getPnpmWorkspaces, + directoryInfo, + getMainStep, +}; |
