From d11d4bade318d5a17d1a5e3860292352e25cc813 Mon Sep 17 00:00:00 2001 From: Yiming Date: Thu, 7 Mar 2024 08:18:14 -0800 Subject: [PATCH] fix: more robust calculation of default location for code generation (#1095) --- package.json | 2 +- packages/ide/jetbrains/build.gradle.kts | 2 +- packages/ide/jetbrains/package.json | 2 +- packages/language/package.json | 2 +- packages/misc/redwood/package.json | 2 +- packages/plugins/openapi/package.json | 2 +- packages/plugins/swr/package.json | 2 +- packages/plugins/tanstack-query/package.json | 2 +- packages/plugins/trpc/package.json | 2 +- packages/runtime/package.json | 2 +- packages/schema/package.json | 2 +- packages/schema/src/plugins/plugin-utils.ts | 32 ++++++++++----- packages/schema/src/utils/pkg-utils.ts | 43 +++++++++++--------- packages/sdk/package.json | 2 +- packages/server/package.json | 2 +- packages/server/src/shared.ts | 9 ++-- packages/testtools/package.json | 2 +- packages/testtools/src/schema.ts | 10 ++++- 18 files changed, 72 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index 54769b34b..6c73b5f25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-monorepo", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "", "scripts": { "build": "pnpm -r build", diff --git a/packages/ide/jetbrains/build.gradle.kts b/packages/ide/jetbrains/build.gradle.kts index 23c8d0b7b..d74358e5f 100644 --- a/packages/ide/jetbrains/build.gradle.kts +++ b/packages/ide/jetbrains/build.gradle.kts @@ -9,7 +9,7 @@ plugins { } group = "dev.zenstack" -version = "2.0.0-alpha.4" +version = "2.0.0-alpha.5" repositories { mavenCentral() diff --git a/packages/ide/jetbrains/package.json b/packages/ide/jetbrains/package.json index db2daea8d..b42a1047b 100644 --- a/packages/ide/jetbrains/package.json +++ b/packages/ide/jetbrains/package.json @@ -1,6 +1,6 @@ { "name": "jetbrains", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "displayName": "ZenStack JetBrains IDE Plugin", "description": "ZenStack JetBrains IDE plugin", "homepage": "https://zenstack.dev", diff --git a/packages/language/package.json b/packages/language/package.json index 315e65049..5ea7cdfa8 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/language", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "displayName": "ZenStack modeling language compiler", "description": "ZenStack modeling language compiler", "homepage": "https://zenstack.dev", diff --git a/packages/misc/redwood/package.json b/packages/misc/redwood/package.json index 9886151b4..2f19b2305 100644 --- a/packages/misc/redwood/package.json +++ b/packages/misc/redwood/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/redwood", "displayName": "ZenStack RedwoodJS Integration", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "CLI and runtime for integrating ZenStack with RedwoodJS projects.", "repository": { "type": "git", diff --git a/packages/plugins/openapi/package.json b/packages/plugins/openapi/package.json index 5d191e2ff..314c71f1e 100644 --- a/packages/plugins/openapi/package.json +++ b/packages/plugins/openapi/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/openapi", "displayName": "ZenStack Plugin and Runtime for OpenAPI", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "ZenStack plugin and runtime supporting OpenAPI", "main": "index.js", "repository": { diff --git a/packages/plugins/swr/package.json b/packages/plugins/swr/package.json index 12652665d..fa22863fa 100644 --- a/packages/plugins/swr/package.json +++ b/packages/plugins/swr/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/swr", "displayName": "ZenStack plugin for generating SWR hooks", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "ZenStack plugin for generating SWR hooks", "main": "index.js", "repository": { diff --git a/packages/plugins/tanstack-query/package.json b/packages/plugins/tanstack-query/package.json index 3da2d8bf8..e4f2e548a 100644 --- a/packages/plugins/tanstack-query/package.json +++ b/packages/plugins/tanstack-query/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/tanstack-query", "displayName": "ZenStack plugin for generating tanstack-query hooks", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "ZenStack plugin for generating tanstack-query hooks", "main": "index.js", "exports": { diff --git a/packages/plugins/trpc/package.json b/packages/plugins/trpc/package.json index c21bccd72..a0ad55223 100644 --- a/packages/plugins/trpc/package.json +++ b/packages/plugins/trpc/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/trpc", "displayName": "ZenStack plugin for tRPC", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "ZenStack plugin for tRPC", "main": "index.js", "repository": { diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 4dcb94daa..93bd0592e 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/runtime", "displayName": "ZenStack Runtime Library", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "Runtime of ZenStack for both client-side and server-side environments.", "repository": { "type": "git", diff --git a/packages/schema/package.json b/packages/schema/package.json index d2113958a..4fe78d2dd 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack Language Tools", "description": "Build scalable web apps with minimum code by defining authorization and validation rules inside the data schema that closer to the database", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "author": { "name": "ZenStack Team" }, diff --git a/packages/schema/src/plugins/plugin-utils.ts b/packages/schema/src/plugins/plugin-utils.ts index d6cc12403..f405604d0 100644 --- a/packages/schema/src/plugins/plugin-utils.ts +++ b/packages/schema/src/plugins/plugin-utils.ts @@ -3,6 +3,7 @@ import { PluginGlobalOptions } from '@zenstackhq/sdk'; import fs from 'fs'; import path from 'path'; import { PluginRunnerOptions } from '../cli/plugin-runner'; +import { getPackageManager } from '../utils/pkg-utils'; export const ALL_OPERATION_KINDS: PolicyOperationKind[] = ['create', 'update', 'postUpdate', 'read', 'delete']; @@ -76,23 +77,32 @@ export function getDefaultOutputFolder(globalOptions?: PluginGlobalOptions) { return path.resolve(globalOptions.output); } - // Find the real runtime module path, it might be a symlink in pnpm - let runtimeModulePath = require.resolve('@zenstackhq/runtime'); - + // for testing, use the local node_modules if (process.env.ZENSTACK_TEST === '1') { - // handle the case when running as tests, resolve relative to CWD - runtimeModulePath = path.resolve(path.join(process.cwd(), 'node_modules', '@zenstackhq', 'runtime')); + return path.join(process.cwd(), 'node_modules', DEFAULT_RUNTIME_LOAD_PATH); } - if (runtimeModulePath) { - // start with the parent folder of @zenstackhq, supposed to be a node_modules folder - while (!runtimeModulePath.endsWith('@zenstackhq') && runtimeModulePath !== '/') { + const { projectRoot } = getPackageManager(__dirname); + if (fs.existsSync(path.join(projectRoot, 'node_modules'))) { + // use the located node_modules folder + return path.join(projectRoot, 'node_modules', DEFAULT_RUNTIME_LOAD_PATH); + } else { + // unable to locate a node_modules folder, fallback to where the runtime + // package resides + + // find the real runtime module path, it might be a symlink in pnpm + let runtimeModulePath = require.resolve('@zenstackhq/runtime'); + + if (runtimeModulePath) { + // start with the parent folder of @zenstackhq, supposed to be a node_modules folder + while (!runtimeModulePath.endsWith('@zenstackhq') && runtimeModulePath !== '/') { + runtimeModulePath = path.join(runtimeModulePath, '..'); + } runtimeModulePath = path.join(runtimeModulePath, '..'); } - runtimeModulePath = path.join(runtimeModulePath, '..'); + const modulesFolder = getNodeModulesFolder(runtimeModulePath); + return modulesFolder ? path.join(modulesFolder, DEFAULT_RUNTIME_LOAD_PATH) : undefined; } - const modulesFolder = getNodeModulesFolder(runtimeModulePath); - return modulesFolder ? path.join(modulesFolder, DEFAULT_RUNTIME_LOAD_PATH) : undefined; } /** diff --git a/packages/schema/src/utils/pkg-utils.ts b/packages/schema/src/utils/pkg-utils.ts index ce41dac34..69c42e1ae 100644 --- a/packages/schema/src/utils/pkg-utils.ts +++ b/packages/schema/src/utils/pkg-utils.ts @@ -1,22 +1,23 @@ import fs from 'node:fs'; import path from 'node:path'; import { execSync } from './exec-utils'; +import { match } from 'ts-pattern'; export type PackageManagers = 'npm' | 'yarn' | 'pnpm'; /** - * 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. + * 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 true ? string[] | undefined : string | undefined +export type FindUp = 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. + * 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 @@ -27,7 +28,12 @@ export type FindUp = e extends true ? string[] | undefined : * @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(names: string[], cwd: string = process.cwd(), multiple: e = false as e, result: string[] = []): FindUp { +export function findUp( + names: string[], + cwd: string = process.cwd(), + multiple: e = false as e, + result: string[] = [] +): FindUp { if (!names.some((name) => !!name)) return undefined; const target = names.find((name) => fs.existsSync(path.join(cwd, name))); if (multiple == false && target) return path.join(cwd, target) as FindUp; @@ -37,23 +43,22 @@ export function findUp(names: string[], cwd: string = return findUp(names, up, multiple, result); } -function getPackageManager(projectPath = '.'): PackageManagers { - const lockFile = findUp(['yarn.lock', 'pnpm-lock.yaml', 'package-lock.json'], projectPath); +export function getPackageManager(searchStartPath = '.') { + const lockFile = findUp(['yarn.lock', 'pnpm-lock.yaml', 'package-lock.json'], searchStartPath); if (!lockFile) { // default use npm - return 'npm'; + return { packageManager: 'npm', lockFile: undefined, projectRoot: searchStartPath }; } - switch (path.basename(lockFile)) { - case 'yarn.lock': - return 'yarn'; - case 'pnpm-lock.yaml': - return 'pnpm'; - default: - return 'npm'; - } + const packageManager = match(path.basename(lockFile)) + .with('yarn.lock', () => 'yarn') + .with('pnpm-lock.yaml', () => 'pnpm') + .otherwise(() => 'npm'); + + return { packageManager, lockFile, projectRoot: path.dirname(lockFile) }; } + export function installPackage( pkg: string, dev: boolean, @@ -106,7 +111,7 @@ 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. + * 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 */ diff --git a/packages/sdk/package.json b/packages/sdk/package.json index d29ecefe1..11f17f3d6 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "ZenStack plugin development SDK", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 40b660ef5..748b68e52 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "displayName": "ZenStack Server-side Adapters", "description": "ZenStack server-side adapters", "homepage": "https://zenstack.dev", diff --git a/packages/server/src/shared.ts b/packages/server/src/shared.ts index 1a9c62119..7538411c5 100644 --- a/packages/server/src/shared.ts +++ b/packages/server/src/shared.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import type { ModelMeta, PolicyDef, ZodSchemas } from '@zenstackhq/runtime'; +import { DEFAULT_RUNTIME_LOAD_PATH, type ModelMeta, type PolicyDef, type ZodSchemas } from '@zenstackhq/runtime'; import path from 'path'; import { AdapterBaseOptions } from './types'; @@ -39,7 +39,8 @@ export function getDefaultModelMeta(loadPath: string | undefined): ModelMeta { if (process.env.ZENSTACK_TEST === '1' && !loadPath) { try { // special handling for running as tests, try resolving relative to CWD - return require(path.join(process.cwd(), 'node_modules', '.zenstack', 'model-meta')).default; + return require(path.join(process.cwd(), 'node_modules', DEFAULT_RUNTIME_LOAD_PATH, 'model-meta')) + .default; } catch { throw new Error('Model meta cannot be loaded. Please make sure "zenstack generate" has been run.'); } @@ -66,7 +67,7 @@ export function getDefaultPolicy(loadPath: string | undefined): PolicyDef { if (process.env.ZENSTACK_TEST === '1' && !loadPath) { try { // special handling for running as tests, try resolving relative to CWD - return require(path.join(process.cwd(), 'node_modules', '.zenstack', 'policy')).default; + return require(path.join(process.cwd(), 'node_modules', DEFAULT_RUNTIME_LOAD_PATH, 'policy')).default; } catch { throw new Error( 'Policy definition cannot be loaded from default location. Please make sure "zenstack generate" has been run.' @@ -97,7 +98,7 @@ export function getDefaultZodSchemas(loadPath: string | undefined): ZodSchemas | if (process.env.ZENSTACK_TEST === '1' && !loadPath) { try { // special handling for running as tests, try resolving relative to CWD - return require(path.join(process.cwd(), 'node_modules', '.zenstack', 'zod')); + return require(path.join(process.cwd(), 'node_modules', DEFAULT_RUNTIME_LOAD_PATH, 'zod')); } catch { return undefined; } diff --git a/packages/testtools/package.json b/packages/testtools/package.json index 35b5078cc..b6ce4df2e 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "2.0.0-alpha.4", + "version": "2.0.0-alpha.5", "description": "ZenStack Test Tools", "main": "index.js", "private": true, diff --git a/packages/testtools/src/schema.ts b/packages/testtools/src/schema.ts index 392b4af4f..ecdad8336 100644 --- a/packages/testtools/src/schema.ts +++ b/packages/testtools/src/schema.ts @@ -2,7 +2,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { DMMF } from '@prisma/generator-helper'; import type { Model } from '@zenstackhq/language/ast'; -import type { AuthUser, CrudContract, EnhancementKind, EnhancementOptions } from '@zenstackhq/runtime'; +import { + DEFAULT_RUNTIME_LOAD_PATH, + type AuthUser, + type CrudContract, + type EnhancementKind, + type EnhancementOptions, +} from '@zenstackhq/runtime'; import { getDMMF } from '@zenstackhq/sdk'; import { execSync } from 'child_process'; import * as fs from 'fs'; @@ -284,7 +290,7 @@ export async function loadSchema(schema: string, options?: SchemaLoadOptions) { ? path.isAbsolute(opt.output) ? opt.output : path.join(projectRoot, opt.output) - : path.join(projectRoot, 'node_modules', '.zenstack'); + : path.join(projectRoot, 'node_modules', DEFAULT_RUNTIME_LOAD_PATH); const policy = require(path.join(outputPath, 'policy')).default; const modelMeta = require(path.join(outputPath, 'model-meta')).default;