From 96a92a34f4b5174d5284a29f83a314c44c3d0677 Mon Sep 17 00:00:00 2001 From: Wim Tibackx Date: Wed, 26 Jun 2024 19:38:16 +0200 Subject: [PATCH] avoid cyclic dependency by expanding the segment of code that is duplicated between schema tests and the testtools package. Might want to look for a better solution in the future. --- packages/schema/package.json | 1 - .../tests/generator/prisma-generator.test.ts | 2 +- packages/schema/tests/utils.ts | 105 ++++++++++++++++++ pnpm-lock.yaml | 3 - 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/packages/schema/package.json b/packages/schema/package.json index e59bdd07f..1c5e0d711 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -135,7 +135,6 @@ "@types/vscode": "^1.56.0", "@vscode/vsce": "^2.19.0", "@zenstackhq/runtime": "workspace:*", - "@zenstackhq/testtools": "workspace:*", "dotenv": "^16.0.3", "esbuild": "^0.15.12", "prisma": "^5.15.0", diff --git a/packages/schema/tests/generator/prisma-generator.test.ts b/packages/schema/tests/generator/prisma-generator.test.ts index 65f848a8d..b347cf4f3 100644 --- a/packages/schema/tests/generator/prisma-generator.test.ts +++ b/packages/schema/tests/generator/prisma-generator.test.ts @@ -7,7 +7,7 @@ import tmp from 'tmp'; import { loadDocument } from '../../src/cli/cli-util'; import { PrismaSchemaGenerator } from '../../src/plugins/prisma/schema-generator'; import { loadModel } from '../utils'; -import { buildPackageJsonContents, initProjectDir } from '@zenstackhq/testtools'; +import { buildPackageJsonContents, initProjectDir } from '../utils'; tmp.setGracefulCleanup(); diff --git a/packages/schema/tests/utils.ts b/packages/schema/tests/utils.ts index e72373f82..b7492342d 100644 --- a/packages/schema/tests/utils.ts +++ b/packages/schema/tests/utils.ts @@ -6,6 +6,11 @@ import * as tmp from 'tmp'; import { URI } from 'vscode-uri'; import { createZModelServices } from '../src/language-server/zmodel-module'; import { mergeBaseModels } from '../src/utils/ast-utils'; +import { execSync } from 'node:child_process'; + +/* This file contains narrowly duplicated contents from the testtools package to avoid a cyclic dependency between testtools and schema */ + +/* Duplicated from testtools model.ts to avoid cyclic dependency */ tmp.setGracefulCleanup(); @@ -97,3 +102,103 @@ export const errorLike = (msg: string) => ({ message: expect.stringContaining(msg), }, }); + + +/* Duplicated from testtools schema.ts to avoid cyclic dependency */ + +export function normalizePath(p: string) { + return p ? p.split(path.sep).join(path.posix.sep) : p; + } + + export function getWorkspaceRoot(start: string) { + let curr = normalizePath(start); + while (curr && curr !== '/') { + if (fs.existsSync(path.join(curr, 'pnpm-workspace.yaml'))) { + return curr; + } else { + curr = normalizePath(path.dirname(curr)); + } + } + return undefined; + } + + /* Duplicated from testtools pnpm-project.ts to avoid cyclic dependency */ + + export const PNPM_STORE_PATH = path.resolve(__dirname, '../../../.pnpm-test-store'); + export const NPM_RC_FILE = '.npmrc'; + export const NPM_RC_CONTENTS = `store-dir = ${PNPM_STORE_PATH}`; + export const PACKAGE_JSON_FILE = 'package.json'; + export const PACKAGE_JSON_CONTENTS = '{"name":"test-project","version":"1.0.0"}'; + + export function preparePackageJson(dependencies: {[key: string]: string} = {}, devDependencies: {[key: string]: string} = {}, includeDefaults: boolean = true): string { + const tmpDir = tmp.dirSync({ unsafeCleanup: true }).name; + console.log(`Loading dependencies into store via temp dir ${tmpDir}`); + try { + const packageJsonContents = buildPackageJsonContents(dependencies, devDependencies, includeDefaults); + + // I considered doing a `pnpm store add` here instead of a plain install. While that worked, I decided against it in the end because it's a secondary way of processing the dependencies and I didn't see a significant downside to just installing and throwing the local project away right after. + initProjectDir(tmpDir, packageJsonContents, false); + + return packageJsonContents; + } finally { + fs.rmSync(tmpDir, {recursive: true, force: true}); + } + } + + export function buildPackageJsonContents(dependencies: {[key: string]: string} = {}, devDependencies: {[key: string]: string} = {}, includeDefaults: boolean = true): string { + if (includeDefaults) { + dependencies = { + "@prisma/client": "^5.14.0", + "zod": "^3.21.0", + "decimal.js": "^10.4.0", + ...dependencies + }, + devDependencies = { + "prisma": "^5.14.0", + "typescript": "^5.4.0", + "@types/node": "^20.0.0", + ...devDependencies + } + } + + const absoluteWorkspacePath = getWorkspaceRoot(__dirname); + + return `{ + "name":"test-project", + "version":"1.0.0", + "dependencies": { + ${Object.entries(dependencies).map(([k, v]) => `"${k}": "${v}"`).join(',\n')} + }, + "devDependencies": { + ${Object.entries(devDependencies).map(([k, v]) => `"${k}": "${v}"`).join(',\n')} + }, + "pnpm": { + "overrides": { + "@zenstackhq/language": "file:${absoluteWorkspacePath}/packages/language/dist", + "@zenstackhq/sdk": "file:${absoluteWorkspacePath}/packages/sdk/dist", + "@zenstackhq/runtime": "file:${absoluteWorkspacePath}/packages/runtime/dist" + } + } + }`; + } + + export function initProjectDir(projectDir: string, packageJsonContents: string, offline = true) { + try { + if (!fs.existsSync(projectDir)) { + fs.mkdirSync(projectDir, { recursive: true }); + } + fs.writeFileSync(path.join(projectDir, PACKAGE_JSON_FILE), packageJsonContents, { flag: 'w+' }); + fs.writeFileSync(path.join(projectDir, NPM_RC_FILE), NPM_RC_CONTENTS, { flag: 'w+' }); + } catch (e) { + console.error(`Failed to set up project dir in ${projectDir}`); + throw e; + } + + try { + execSync(`pnpm install ${offline ? '--prefer-offline ' : ''}--ignore-workspace`, {cwd: projectDir, stdio: 'ignore'}); + } catch (e) { + console.error(`Failed to initialize project dependencies in ${projectDir}${offline ? '(offline mode)' : '(online mode)'}`); + throw e; + } + } + \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1cf81de2..dfeda8f4e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -604,9 +604,6 @@ importers: '@zenstackhq/runtime': specifier: workspace:* version: link:../runtime/dist - '@zenstackhq/testtools': - specifier: workspace:* - version: link:../testtools/dist dotenv: specifier: ^16.0.3 version: 16.0.3