UNPKG

@deftomat/opinionated

Version:

Opinionated tooling for JavaScript & TypeScript projects.

103 lines (102 loc) 3.59 kB
import chalk from 'chalk'; import { findUpSync } from 'find-up'; import { globSync } from 'glob'; import fs from 'node:fs'; import path from 'node:path'; import { ToolError } from './errors.js'; import { createGitWorkflow } from './git.js'; const { bold, red } = chalk; export function isMonorepoContext(context) { return context.type === 'monorepo'; } export function isMonorepoPackageContext(context) { return context.type === 'monorepo-package'; } export function isPackageContext(context) { return context.type === 'package'; } /** * Returns the tool context for the given working directory. */ export function describeContext(cwd) { try { const specConnector = toSpecConnector(`${cwd}/package.json`); const spec = specConnector.get(); const packageContext = { type: 'package', projectRoot: cwd, projectSpec: specConnector, packageRoot: cwd, packageSpec: specConnector, cachePath: toCachePath(cwd), git: createGitWorkflow(cwd) }; if (spec.workspaces) { const context = { type: 'monorepo', projectRoot: cwd, projectSpec: specConnector, packages: listProjectPackages(cwd), packageRoot: undefined, packageSpec: undefined, cachePath: toCachePath(cwd), git: createGitWorkflow(cwd) }; return context; } const parent = findUpSync('package.json', { cwd: `${cwd}/../` }); if (parent == null) return packageContext; const parentSpecConnector = toSpecConnector(parent); const parentSpec = parentSpecConnector.get(); if (parentSpec.workspaces) { const parentRoot = path.dirname(parent); const context = { type: 'monorepo-package', projectRoot: parentRoot, projectSpec: parentSpecConnector, packageRoot: cwd, packageSpec: specConnector, cachePath: toCachePath(parentRoot), git: createGitWorkflow(parentRoot) }; return context; } return packageContext; } catch (error) { if (error.code === 'ENOENT') { throw new ToolError(red(`No ${bold('package.json')} found! Please make sure that you run this command in the root of JS/TS project.`)); } throw Error(`Unexpected error:\n${error}`); } } function toSpecConnector(path) { return { path, get() { return JSON.parse(fs.readFileSync(path).toString()); }, set(content) { fs.writeFileSync(path, JSON.stringify(content, null, 2)); } }; } function toCachePath(projectRoot) { return `${projectRoot}/node_modules/.cache/opinionated`; } /** * Returns a list of packages and their absolute paths in the project. * * If the project is a part of the monorepo, then it returns all packages. * Otherwise, it returns the project itself as a package. */ function listProjectPackages(projectRoot) { const manifest = JSON.parse(fs.readFileSync(`${projectRoot}/package.json`).toString()); if (manifest.workspaces == null) return [projectRoot]; return manifest.workspaces .flatMap(pattern => globSync(pattern, { cwd: projectRoot, absolute: true })) .filter(root => fs.lstatSync(root).isDirectory()) .filter(root => fs.existsSync(`${root}/package.json`)); }