Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: find up #1019

Merged
merged 6 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/schema/src/cli/cli-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { PLUGIN_MODULE_NAME, STD_LIB_MODULE_NAME } from '../language-server/cons
import { ZModelFormatter } from '../language-server/zmodel-formatter';
import { createZModelServices, ZModelServices } from '../language-server/zmodel-module';
import { mergeBaseModel, resolveImport, resolveTransitiveImports } from '../utils/ast-utils';
import { findPackageJson } from '../utils/pkg-utils';
import { findUp } from '../utils/pkg-utils';
import { getVersion } from '../utils/version-utils';
import { CliError } from './cli-error';

Expand Down Expand Up @@ -280,7 +280,7 @@ export async function formatDocument(fileName: string) {

export function getDefaultSchemaLocation() {
// handle override from package.json
const pkgJsonPath = findPackageJson();
const pkgJsonPath = findUp(['package.json']);
if (pkgJsonPath) {
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
if (typeof pkgJson?.zenstack?.schema === 'string') {
Expand Down
4 changes: 2 additions & 2 deletions packages/schema/src/plugins/prisma/schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { name } from '.';
import { getStringLiteral } from '../../language-server/validator/utils';
import telemetry from '../../telemetry';
import { execPackage } from '../../utils/exec-utils';
import { findPackageJson } from '../../utils/pkg-utils';
import { findUp } from '../../utils/pkg-utils';
import {
ModelFieldType,
AttributeArg as PrismaAttributeArg,
Expand Down Expand Up @@ -450,7 +450,7 @@ export default class PrismaSchemaGenerator {

export function getDefaultPrismaOutputFile(schemaPath: string) {
// handle override from package.json
const pkgJsonPath = findPackageJson(path.dirname(schemaPath));
const pkgJsonPath = findUp(['package.json'], path.dirname(schemaPath));
if (pkgJsonPath) {
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
if (typeof pkgJson?.zenstack?.prisma === 'string') {
Expand Down
53 changes: 39 additions & 14 deletions packages/schema/src/utils/pkg-utils.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
import fs from 'fs';
import path from 'path';
import fs from 'node:fs';
import path from 'node:path';
import { execSync } from './exec-utils';

export type PackageManagers = 'npm' | 'yarn' | 'pnpm';

function findUp(names: string[], cwd: string): string | undefined {
let dir = cwd;
// eslint-disable-next-line no-constant-condition
while (true) {
const target = names.find((name) => fs.existsSync(path.join(dir, name)));
if (target) return target;

const up = path.resolve(dir, '..');
if (up === dir) return undefined; // it'll fail anyway
dir = up;
}
/**
* A type named FindUp that takes a type parameter e which extends boolean.
* If e extends true, it returns a union type of string[] or undefined.
* If e does not extend true, it returns a union type of string or undefined.
*
* @export
* @template e A type parameter that extends boolean
*/
export type FindUp<e extends boolean> = e extends true ? string[] | undefined : string | undefined
/**
* Find and return file paths by searching parent directories based on the given names list and current working directory (cwd) path.
* Optionally return a single path or multiple paths.
* If multiple allowed, return all paths found.
* If no paths are found, return undefined.
*
* @export
* @template [e=false]
* @param names An array of strings representing names to search for within the directory
* @param cwd A string representing the current working directory
* @param [multiple=false as e] A boolean flag indicating whether to search for multiple levels. Useful for finding node_modules directories...
* @param [result=[]] An array of strings representing the accumulated results used in multiple results
* @returns Path(s) to a specific file or folder within the directory or parent directories
*/
export function findUp<e extends boolean = false>(names: string[], cwd: string = process.cwd(), multiple: e = false as e, result: string[] = []): FindUp<e> {
if (!names.some((name) => !!name)) return undefined;
ymc9 marked this conversation as resolved.
Show resolved Hide resolved
const target = names.find((name) => fs.existsSync(path.join(cwd, name)));
if (multiple == false && target) return path.join(cwd, target) as FindUp<e>;
if (target) result.push(path.join(cwd, target));
const up = path.resolve(cwd, '..');
if (up === cwd) return (multiple && result.length > 0 ? result : undefined) as FindUp<e>; // it'll fail anyway
return findUp(names, up, multiple, result);
}

function getPackageManager(projectPath = '.'): PackageManagers {
Expand Down Expand Up @@ -85,6 +105,11 @@ export function ensurePackage(
}
}

/**
* A function that searches for the nearest package.json file starting from the provided search path or the current working directory if no search path is provided.
* It iterates through the directory structure going one level up at a time until it finds a package.json file. If no package.json file is found, it returns undefined.
* @deprecated Use findUp instead @see findUp
*/
export function findPackageJson(searchPath?: string) {
let currDir = searchPath ?? process.cwd();
while (currDir) {
Expand All @@ -102,7 +127,7 @@ export function findPackageJson(searchPath?: string) {
}

export function getPackageJson(searchPath?: string) {
const pkgJsonPath = findPackageJson(searchPath);
const pkgJsonPath = findUp(['package.json'], searchPath ?? process.cwd());
if (pkgJsonPath) {
return JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
} else {
Expand Down
Loading