@zenstackhq/testtools 3.0.0-beta.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -31,13 +31,36 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var src_exports = {};
33
33
  __export(src_exports, {
34
+ TEST_PG_CONFIG: () => TEST_PG_CONFIG,
35
+ TEST_PG_URL: () => TEST_PG_URL,
36
+ createPolicyTestClient: () => createPolicyTestClient,
37
+ createTestClient: () => createTestClient,
34
38
  createTestProject: () => createTestProject,
35
39
  generateTsSchema: () => generateTsSchema,
36
40
  generateTsSchemaFromFile: () => generateTsSchemaFromFile,
37
- generateTsSchemaInPlace: () => generateTsSchemaInPlace
41
+ generateTsSchemaInPlace: () => generateTsSchemaInPlace,
42
+ getTestDbProvider: () => getTestDbProvider,
43
+ loadSchema: () => loadSchema,
44
+ loadSchemaWithError: () => loadSchemaWithError,
45
+ testLogger: () => testLogger
38
46
  });
39
47
  module.exports = __toCommonJS(src_exports);
40
48
 
49
+ // src/client.ts
50
+ var import_common_helpers2 = require("@zenstackhq/common-helpers");
51
+ var import_orm = require("@zenstackhq/orm");
52
+ var import_plugin_policy = require("@zenstackhq/plugin-policy");
53
+ var import_sdk2 = require("@zenstackhq/sdk");
54
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
55
+ var import_glob = require("glob");
56
+ var import_kysely = require("kysely");
57
+ var import_node_child_process2 = require("child_process");
58
+ var import_node_crypto2 = require("crypto");
59
+ var import_node_fs3 = __toESM(require("fs"), 1);
60
+ var import_node_path3 = __toESM(require("path"), 1);
61
+ var import_pg = require("pg");
62
+ var import_vitest2 = require("vitest");
63
+
41
64
  // src/project.ts
42
65
  var import_node_fs = __toESM(require("fs"), 1);
43
66
  var import_node_path = __toESM(require("path"), 1);
@@ -57,7 +80,7 @@ function createTestProject(zmodelContent) {
57
80
  const zenstackPackages = [
58
81
  "language",
59
82
  "sdk",
60
- "runtime",
83
+ "orm",
61
84
  "cli"
62
85
  ];
63
86
  import_node_fs.default.mkdirSync(import_node_path.default.join(workDir, "node_modules/@zenstackhq"));
@@ -90,12 +113,27 @@ function createTestProject(zmodelContent) {
90
113
  __name(createTestProject, "createTestProject");
91
114
 
92
115
  // src/schema.ts
93
- var import_language = require("@zenstackhq/language");
116
+ var import_common_helpers = require("@zenstackhq/common-helpers");
94
117
  var import_sdk = require("@zenstackhq/sdk");
95
118
  var import_node_child_process = require("child_process");
119
+ var import_node_crypto = __toESM(require("crypto"), 1);
96
120
  var import_node_fs2 = __toESM(require("fs"), 1);
121
+ var import_node_os = __toESM(require("os"), 1);
97
122
  var import_node_path2 = __toESM(require("path"), 1);
98
123
  var import_ts_pattern = require("ts-pattern");
124
+ var import_vitest = require("vitest");
125
+
126
+ // src/utils.ts
127
+ var import_language = require("@zenstackhq/language");
128
+ function loadDocumentWithPlugins(filePath) {
129
+ const pluginModelFiles = [
130
+ require.resolve("@zenstackhq/plugin-policy/plugin.zmodel")
131
+ ];
132
+ return (0, import_language.loadDocument)(filePath, pluginModelFiles);
133
+ }
134
+ __name(loadDocumentWithPlugins, "loadDocumentWithPlugins");
135
+
136
+ // src/schema.ts
99
137
  function makePrelude(provider, dbUrl) {
100
138
  return (0, import_ts_pattern.match)(provider).with("sqlite", () => {
101
139
  return `
@@ -114,22 +152,30 @@ datasource db {
114
152
  }).exhaustive();
115
153
  }
116
154
  __name(makePrelude, "makePrelude");
117
- async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles) {
155
+ function replacePlaceholders(schemaText, provider, dbUrl) {
156
+ const url = dbUrl ?? (provider === "sqlite" ? "file:./test.db" : "postgres://postgres:postgres@localhost:5432/db");
157
+ return schemaText.replace(/\$DB_URL/g, url).replace(/\$PROVIDER/g, provider);
158
+ }
159
+ __name(replacePlaceholders, "replacePlaceholders");
160
+ async function generateTsSchema(schemaText, provider = "sqlite", dbUrl, extraSourceFiles, withLiteSchema) {
118
161
  const workDir = createTestProject();
119
162
  const zmodelPath = import_node_path2.default.join(workDir, "schema.zmodel");
120
163
  const noPrelude = schemaText.includes("datasource ");
121
164
  import_node_fs2.default.writeFileSync(zmodelPath, `${noPrelude ? "" : makePrelude(provider, dbUrl)}
122
165
 
123
- ${schemaText}`);
124
- const result = await (0, import_language.loadDocument)(zmodelPath);
166
+ ${replacePlaceholders(schemaText, provider, dbUrl)}`);
167
+ const result = await loadDocumentWithPlugins(zmodelPath);
125
168
  if (!result.success) {
126
169
  throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);
127
170
  }
128
171
  const generator = new import_sdk.TsSchemaGenerator();
129
- await generator.generate(result.model, workDir);
172
+ await generator.generate(result.model, {
173
+ outDir: workDir,
174
+ lite: withLiteSchema
175
+ });
130
176
  if (extraSourceFiles) {
131
177
  for (const [fileName, content] of Object.entries(extraSourceFiles)) {
132
- const filePath = import_node_path2.default.resolve(workDir, `${fileName}.ts`);
178
+ const filePath = import_node_path2.default.resolve(workDir, !fileName.endsWith(".ts") ? `${fileName}.ts` : fileName);
133
179
  import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(filePath), {
134
180
  recursive: true
135
181
  });
@@ -148,9 +194,15 @@ async function compileAndLoad(workDir) {
148
194
  stdio: "inherit"
149
195
  });
150
196
  const module2 = await import(import_node_path2.default.join(workDir, "schema.js"));
197
+ let moduleLite;
198
+ try {
199
+ moduleLite = await import(import_node_path2.default.join(workDir, "schema-lite.js"));
200
+ } catch {
201
+ }
151
202
  return {
152
203
  workDir,
153
- schema: module2.schema
204
+ schema: module2.schema,
205
+ schemaLite: moduleLite?.schema
154
206
  };
155
207
  }
156
208
  __name(compileAndLoad, "compileAndLoad");
@@ -161,20 +213,388 @@ function generateTsSchemaFromFile(filePath) {
161
213
  __name(generateTsSchemaFromFile, "generateTsSchemaFromFile");
162
214
  async function generateTsSchemaInPlace(schemaPath) {
163
215
  const workDir = import_node_path2.default.dirname(schemaPath);
164
- const result = await (0, import_language.loadDocument)(schemaPath);
216
+ const result = await loadDocumentWithPlugins(schemaPath);
165
217
  if (!result.success) {
166
218
  throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);
167
219
  }
168
220
  const generator = new import_sdk.TsSchemaGenerator();
169
- await generator.generate(result.model, workDir);
221
+ await generator.generate(result.model, {
222
+ outDir: workDir
223
+ });
170
224
  return compileAndLoad(workDir);
171
225
  }
172
226
  __name(generateTsSchemaInPlace, "generateTsSchemaInPlace");
227
+ async function loadSchema(schema, additionalSchemas) {
228
+ if (!schema.includes("datasource ")) {
229
+ schema = `${makePrelude("sqlite")}
230
+
231
+ ${schema}`;
232
+ }
233
+ const tempDir = import_node_fs2.default.mkdtempSync(import_node_path2.default.join(import_node_os.default.tmpdir(), "zenstack-schema"));
234
+ const tempFile = import_node_path2.default.join(tempDir, `schema.zmodel`);
235
+ import_node_fs2.default.writeFileSync(tempFile, schema);
236
+ if (additionalSchemas) {
237
+ for (const [fileName, content] of Object.entries(additionalSchemas)) {
238
+ let name = fileName;
239
+ if (!name.endsWith(".zmodel")) {
240
+ name += ".zmodel";
241
+ }
242
+ const filePath = import_node_path2.default.join(tempDir, name);
243
+ import_node_fs2.default.writeFileSync(filePath, content);
244
+ }
245
+ }
246
+ const r = await loadDocumentWithPlugins(tempFile);
247
+ (0, import_vitest.expect)(r).toSatisfy((r2) => r2.success, `Failed to load schema: ${r.errors?.map((e) => e.toString()).join(", ")}`);
248
+ (0, import_common_helpers.invariant)(r.success);
249
+ return r.model;
250
+ }
251
+ __name(loadSchema, "loadSchema");
252
+ async function loadSchemaWithError(schema, error) {
253
+ if (!schema.includes("datasource ")) {
254
+ schema = `${makePrelude("sqlite")}
255
+
256
+ ${schema}`;
257
+ }
258
+ const tempFile = import_node_path2.default.join(import_node_os.default.tmpdir(), `zenstack-schema-${import_node_crypto.default.randomUUID()}.zmodel`);
259
+ import_node_fs2.default.writeFileSync(tempFile, schema);
260
+ const r = await loadDocumentWithPlugins(tempFile);
261
+ (0, import_vitest.expect)(r.success).toBe(false);
262
+ (0, import_common_helpers.invariant)(!r.success);
263
+ if (typeof error === "string") {
264
+ (0, import_vitest.expect)(r).toSatisfy((r2) => r2.errors.some((e) => e.toString().toLowerCase().includes(error.toLowerCase())), `Expected error message to include "${error}" but got: ${r.errors.map((e) => e.toString()).join(", ")}`);
265
+ } else {
266
+ (0, import_vitest.expect)(r).toSatisfy((r2) => r2.errors.some((e) => error.test(e)), `Expected error message to match "${error}" but got: ${r.errors.map((e) => e.toString()).join(", ")}`);
267
+ }
268
+ }
269
+ __name(loadSchemaWithError, "loadSchemaWithError");
270
+
271
+ // src/client.ts
272
+ function getTestDbProvider() {
273
+ const val = process.env["TEST_DB_PROVIDER"] ?? "sqlite";
274
+ if (![
275
+ "sqlite",
276
+ "postgresql"
277
+ ].includes(val)) {
278
+ throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);
279
+ }
280
+ return val;
281
+ }
282
+ __name(getTestDbProvider, "getTestDbProvider");
283
+ var TEST_PG_CONFIG = {
284
+ host: process.env["TEST_PG_HOST"] ?? "localhost",
285
+ port: process.env["TEST_PG_PORT"] ? parseInt(process.env["TEST_PG_PORT"]) : 5432,
286
+ user: process.env["TEST_PG_USER"] ?? "postgres",
287
+ password: process.env["TEST_PG_PASSWORD"] ?? "postgres"
288
+ };
289
+ var TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;
290
+ async function createTestClient(schema, options) {
291
+ let workDir = options?.workDir;
292
+ let _schema;
293
+ const provider = options?.provider ?? getTestDbProvider() ?? "sqlite";
294
+ const dbName = options?.dbName ?? getTestDbName(provider);
295
+ const dbUrl = provider === "sqlite" ? `file:${dbName}` : `${TEST_PG_URL}/${dbName}`;
296
+ let model;
297
+ if (typeof schema === "string") {
298
+ const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, void 0);
299
+ workDir = generated.workDir;
300
+ model = generated.model;
301
+ _schema = {
302
+ ...generated.schema,
303
+ provider: {
304
+ ...generated.schema.provider,
305
+ type: provider
306
+ }
307
+ };
308
+ } else {
309
+ _schema = {
310
+ ...schema,
311
+ provider: {
312
+ type: provider
313
+ }
314
+ };
315
+ workDir ??= createTestProject();
316
+ if (options?.schemaFile) {
317
+ let schemaContent = import_node_fs3.default.readFileSync(options.schemaFile, "utf-8");
318
+ if (dbUrl) {
319
+ schemaContent = schemaContent.replace(/datasource\s+db\s*{[^}]*}/m, `datasource db {
320
+ provider = '${provider}'
321
+ url = '${dbUrl}'
322
+ ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(", ")}]` : ""}
323
+ }`);
324
+ }
325
+ import_node_fs3.default.writeFileSync(import_node_path3.default.join(workDir, "schema.zmodel"), schemaContent);
326
+ }
327
+ }
328
+ (0, import_common_helpers2.invariant)(workDir);
329
+ const { plugins, ...rest } = options ?? {};
330
+ const _options = {
331
+ ...rest
332
+ };
333
+ if (options?.debug) {
334
+ console.log(`Work directory: ${workDir}`);
335
+ console.log(`Database name: ${dbName}`);
336
+ _options.log = testLogger;
337
+ }
338
+ if (options?.dbFile) {
339
+ if (provider !== "sqlite") {
340
+ throw new Error("dbFile option is only supported for sqlite provider");
341
+ }
342
+ import_node_fs3.default.copyFileSync(options.dbFile, import_node_path3.default.join(workDir, dbName));
343
+ }
344
+ if (options?.copyFiles) {
345
+ const state = import_vitest2.expect.getState();
346
+ const currentTestPath = state.testPath;
347
+ if (!currentTestPath) {
348
+ throw new Error("Unable to determine current test file path");
349
+ }
350
+ for (const { globPattern, destination } of options.copyFiles) {
351
+ const files = import_glob.glob.sync(globPattern, {
352
+ cwd: import_node_path3.default.dirname(currentTestPath)
353
+ });
354
+ for (const file of files) {
355
+ const src = import_node_path3.default.resolve(import_node_path3.default.dirname(currentTestPath), file);
356
+ const dest = import_node_path3.default.resolve(workDir, destination, import_node_path3.default.basename(file));
357
+ import_node_fs3.default.mkdirSync(import_node_path3.default.dirname(dest), {
358
+ recursive: true
359
+ });
360
+ import_node_fs3.default.copyFileSync(src, dest);
361
+ }
362
+ }
363
+ }
364
+ if (!options?.dbFile) {
365
+ if (options?.usePrismaPush) {
366
+ (0, import_common_helpers2.invariant)(typeof schema === "string" || options?.schemaFile, "a schema file must be provided when using prisma db push");
367
+ if (!model) {
368
+ const r = await loadDocumentWithPlugins(import_node_path3.default.join(workDir, "schema.zmodel"));
369
+ if (!r.success) {
370
+ throw new Error(r.errors.join("\n"));
371
+ }
372
+ model = r.model;
373
+ }
374
+ const prismaSchema = new import_sdk2.PrismaSchemaGenerator(model);
375
+ const prismaSchemaText = await prismaSchema.generate();
376
+ import_node_fs3.default.writeFileSync(import_node_path3.default.resolve(workDir, "schema.prisma"), prismaSchemaText);
377
+ (0, import_node_child_process2.execSync)("npx prisma db push --schema ./schema.prisma --skip-generate --force-reset", {
378
+ cwd: workDir,
379
+ stdio: "ignore"
380
+ });
381
+ } else {
382
+ if (provider === "postgresql") {
383
+ (0, import_common_helpers2.invariant)(dbName, "dbName is required");
384
+ const pgClient = new import_pg.Client(TEST_PG_CONFIG);
385
+ await pgClient.connect();
386
+ await pgClient.query(`DROP DATABASE IF EXISTS "${dbName}"`);
387
+ await pgClient.query(`CREATE DATABASE "${dbName}"`);
388
+ await pgClient.end();
389
+ }
390
+ }
391
+ }
392
+ if (provider === "postgresql") {
393
+ _options.dialect = new import_kysely.PostgresDialect({
394
+ pool: new import_pg.Pool({
395
+ ...TEST_PG_CONFIG,
396
+ database: dbName
397
+ })
398
+ });
399
+ } else {
400
+ _options.dialect = new import_kysely.SqliteDialect({
401
+ database: new import_better_sqlite3.default(import_node_path3.default.join(workDir, dbName))
402
+ });
403
+ }
404
+ let client = new import_orm.ZenStackClient(_schema, _options);
405
+ if (!options?.usePrismaPush && !options?.dbFile) {
406
+ await client.$pushSchema();
407
+ }
408
+ if (plugins) {
409
+ for (const plugin of plugins) {
410
+ client = client.$use(plugin);
411
+ }
412
+ }
413
+ return client;
414
+ }
415
+ __name(createTestClient, "createTestClient");
416
+ async function createPolicyTestClient(schema, options) {
417
+ return createTestClient(schema, {
418
+ ...options,
419
+ plugins: [
420
+ ...options?.plugins ?? [],
421
+ new import_plugin_policy.PolicyPlugin()
422
+ ]
423
+ });
424
+ }
425
+ __name(createPolicyTestClient, "createPolicyTestClient");
426
+ function testLogger(e) {
427
+ console.log(e.query.sql, e.query.parameters);
428
+ }
429
+ __name(testLogger, "testLogger");
430
+ function getTestDbName(provider) {
431
+ if (provider === "sqlite") {
432
+ return "./test.db";
433
+ }
434
+ const testName = import_vitest2.expect.getState().currentTestName ?? "unnamed";
435
+ const testPath = import_vitest2.expect.getState().testPath ?? "";
436
+ const digest = (0, import_node_crypto2.createHash)("md5").update(testName + testPath).digest("hex");
437
+ return "test_" + testName.toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").substring(0, 30) + digest.slice(0, 6);
438
+ }
439
+ __name(getTestDbName, "getTestDbName");
440
+
441
+ // src/vitest-ext.ts
442
+ var import_orm2 = require("@zenstackhq/orm");
443
+ var import_vitest3 = require("vitest");
444
+ function isPromise(value) {
445
+ return typeof value.then === "function" && typeof value.catch === "function";
446
+ }
447
+ __name(isPromise, "isPromise");
448
+ function expectErrorReason(err, errorReason) {
449
+ if (err instanceof import_orm2.ORMError && err.reason === errorReason) {
450
+ return {
451
+ message: /* @__PURE__ */ __name(() => "", "message"),
452
+ pass: true
453
+ };
454
+ } else {
455
+ return {
456
+ message: /* @__PURE__ */ __name(() => `expected ORMError of reason ${errorReason}, got ${err}`, "message"),
457
+ pass: false
458
+ };
459
+ }
460
+ }
461
+ __name(expectErrorReason, "expectErrorReason");
462
+ function expectErrorMessages(expectedMessages, message) {
463
+ for (const m of expectedMessages) {
464
+ if (!message.toLowerCase().includes(m.toLowerCase())) {
465
+ return {
466
+ message: /* @__PURE__ */ __name(() => `expected message not found in error: ${m}, got message: ${message}`, "message"),
467
+ pass: false
468
+ };
469
+ }
470
+ }
471
+ return void 0;
472
+ }
473
+ __name(expectErrorMessages, "expectErrorMessages");
474
+ import_vitest3.expect.extend({
475
+ async toResolveTruthy(received) {
476
+ if (!isPromise(received)) {
477
+ return {
478
+ message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
479
+ pass: false
480
+ };
481
+ }
482
+ const r = await received;
483
+ return {
484
+ pass: !!r,
485
+ message: /* @__PURE__ */ __name(() => `Expected promise to resolve to a truthy value, but got ${r}`, "message")
486
+ };
487
+ },
488
+ async toResolveFalsy(received) {
489
+ if (!isPromise(received)) {
490
+ return {
491
+ message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
492
+ pass: false
493
+ };
494
+ }
495
+ const r = await received;
496
+ return {
497
+ pass: !r,
498
+ message: /* @__PURE__ */ __name(() => `Expected promise to resolve to a falsy value, but got ${r}`, "message")
499
+ };
500
+ },
501
+ async toResolveNull(received) {
502
+ if (!isPromise(received)) {
503
+ return {
504
+ message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
505
+ pass: false
506
+ };
507
+ }
508
+ const r = await received;
509
+ return {
510
+ pass: r === null,
511
+ message: /* @__PURE__ */ __name(() => `Expected promise to resolve to a null value, but got ${r}`, "message")
512
+ };
513
+ },
514
+ async toResolveWithLength(received, length) {
515
+ const r = await received;
516
+ return {
517
+ pass: Array.isArray(r) && r.length === length,
518
+ message: /* @__PURE__ */ __name(() => `Expected promise to resolve with an array with length ${length}, but got ${r}`, "message")
519
+ };
520
+ },
521
+ async toBeRejectedNotFound(received) {
522
+ if (!isPromise(received)) {
523
+ return {
524
+ message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
525
+ pass: false
526
+ };
527
+ }
528
+ try {
529
+ await received;
530
+ } catch (err) {
531
+ return expectErrorReason(err, import_orm2.ORMErrorReason.NOT_FOUND);
532
+ }
533
+ return {
534
+ message: /* @__PURE__ */ __name(() => `expected NotFoundError, got no error`, "message"),
535
+ pass: false
536
+ };
537
+ },
538
+ async toBeRejectedByPolicy(received, expectedMessages) {
539
+ if (!isPromise(received)) {
540
+ return {
541
+ message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
542
+ pass: false
543
+ };
544
+ }
545
+ try {
546
+ await received;
547
+ } catch (err) {
548
+ if (expectedMessages && err instanceof import_orm2.ORMError && err.reason === import_orm2.ORMErrorReason.REJECTED_BY_POLICY) {
549
+ const r = expectErrorMessages(expectedMessages, err.message || "");
550
+ if (r) {
551
+ return r;
552
+ }
553
+ }
554
+ return expectErrorReason(err, import_orm2.ORMErrorReason.REJECTED_BY_POLICY);
555
+ }
556
+ return {
557
+ message: /* @__PURE__ */ __name(() => `expected PolicyError, got no error`, "message"),
558
+ pass: false
559
+ };
560
+ },
561
+ async toBeRejectedByValidation(received, expectedMessages) {
562
+ if (!isPromise(received)) {
563
+ return {
564
+ message: /* @__PURE__ */ __name(() => "a promise is expected", "message"),
565
+ pass: false
566
+ };
567
+ }
568
+ try {
569
+ await received;
570
+ } catch (err) {
571
+ if (expectedMessages && err instanceof import_orm2.ORMError && err.reason === import_orm2.ORMErrorReason.INVALID_INPUT) {
572
+ const r = expectErrorMessages(expectedMessages, err.message || "");
573
+ if (r) {
574
+ return r;
575
+ }
576
+ }
577
+ return expectErrorReason(err, import_orm2.ORMErrorReason.INVALID_INPUT);
578
+ }
579
+ return {
580
+ message: /* @__PURE__ */ __name(() => `expected InputValidationError, got no error`, "message"),
581
+ pass: false
582
+ };
583
+ }
584
+ });
173
585
  // Annotate the CommonJS export names for ESM import in node:
174
586
  0 && (module.exports = {
587
+ TEST_PG_CONFIG,
588
+ TEST_PG_URL,
589
+ createPolicyTestClient,
590
+ createTestClient,
175
591
  createTestProject,
176
592
  generateTsSchema,
177
593
  generateTsSchemaFromFile,
178
- generateTsSchemaInPlace
594
+ generateTsSchemaInPlace,
595
+ getTestDbProvider,
596
+ loadSchema,
597
+ loadSchemaWithError,
598
+ testLogger
179
599
  });
180
600
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/project.ts","../src/schema.ts"],"sourcesContent":["export * from './project';\nexport * from './schema';\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'runtime', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { loadDocument } from '@zenstackhq/language';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport type { SchemaDef } from '@zenstackhq/sdk/schema';\nimport { execSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { createTestProject } from './project';\n\nfunction makePrelude(provider: 'sqlite' | 'postgresql', dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(zmodelPath, `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${schemaText}`);\n\n const result = await loadDocument(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, workDir);\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, `${fileName}.ts`);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n return { workDir, schema: module.schema as SchemaDef };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocument(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, workDir);\n return compileAndLoad(workDir);\n}\n"],"mappings":"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","names":["createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","import_node_fs","import_node_path","makePrelude","provider","dbUrl","match","with","exhaustive","generateTsSchema","schemaText","extraSourceFiles","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","result","loadDocument","success","Error","errors","generator","TsSchemaGenerator","generate","model","fileName","content","Object","entries","filePath","resolve","mkdirSync","dirname","recursive","compileAndLoad","execSync","cwd","stdio","module","schema","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/project.ts","../src/schema.ts","../src/utils.ts","../src/vitest-ext.ts"],"sourcesContent":["export * from './client';\nexport * from './project';\nexport * from './schema';\nexport * from './vitest-ext';\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { Model } from '@zenstackhq/language/ast';\nimport { ZenStackClient, type ClientContract, type ClientOptions } from '@zenstackhq/orm';\nimport type { SchemaDef } from '@zenstackhq/orm/schema';\nimport { PolicyPlugin } from '@zenstackhq/plugin-policy';\nimport { PrismaSchemaGenerator } from '@zenstackhq/sdk';\nimport SQLite from 'better-sqlite3';\nimport { glob } from 'glob';\nimport { PostgresDialect, SqliteDialect, type LogEvent } from 'kysely';\nimport { execSync } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { Client as PGClient, Pool } from 'pg';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { generateTsSchema } from './schema';\nimport { loadDocumentWithPlugins } from './utils';\n\nexport function getTestDbProvider() {\n const val = process.env['TEST_DB_PROVIDER'] ?? 'sqlite';\n if (!['sqlite', 'postgresql'].includes(val!)) {\n throw new Error(`Invalid TEST_DB_PROVIDER value: ${val}`);\n }\n return val as 'sqlite' | 'postgresql';\n}\n\nexport const TEST_PG_CONFIG = {\n host: process.env['TEST_PG_HOST'] ?? 'localhost',\n port: process.env['TEST_PG_PORT'] ? parseInt(process.env['TEST_PG_PORT']) : 5432,\n user: process.env['TEST_PG_USER'] ?? 'postgres',\n password: process.env['TEST_PG_PASSWORD'] ?? 'postgres',\n};\n\nexport const TEST_PG_URL = `postgres://${TEST_PG_CONFIG.user}:${TEST_PG_CONFIG.password}@${TEST_PG_CONFIG.host}:${TEST_PG_CONFIG.port}`;\n\ntype ExtraTestClientOptions = {\n /**\n * Database provider\n */\n provider?: 'sqlite' | 'postgresql';\n\n /**\n * The main ZModel file. Only used when `usePrismaPush` is true and `schema` is an object.\n */\n schemaFile?: string;\n\n /**\n * Database name. If not provided, a name will be generated based on the test name.\n */\n dbName?: string;\n\n /**\n * Use `prisma db push` instead of ZenStack's `$pushSchema` for database initialization.\n */\n usePrismaPush?: boolean;\n\n /**\n * Extra source files to create and compile.\n */\n extraSourceFiles?: Record<string, string>;\n\n /**\n * Working directory for the test client. If not provided, a temporary directory will be created.\n */\n workDir?: string;\n\n /**\n * Debug mode.\n */\n debug?: boolean;\n\n /**\n * A sqlite database file to be used for the test. Only supported for sqlite provider.\n */\n dbFile?: string;\n\n /**\n * PostgreSQL extensions to be added to the datasource. Only supported for postgresql provider.\n */\n dataSourceExtensions?: string[];\n\n /**\n * Additional files to be copied to the working directory. The glob pattern is relative to the test file.\n */\n copyFiles?: {\n globPattern: string;\n destination: string;\n }[];\n};\n\nexport type CreateTestClientOptions<Schema extends SchemaDef> = Omit<ClientOptions<Schema>, 'dialect'> &\n ExtraTestClientOptions;\n\nexport async function createTestClient<\n Schema extends SchemaDef,\n Options extends ClientOptions<Schema>,\n CreateOptions = Omit<Options, 'dialect'>,\n>(schema: Schema, options?: CreateOptions): Promise<ClientContract<Schema, Options>>;\nexport async function createTestClient(schema: string, options?: CreateTestClientOptions<SchemaDef>): Promise<any>;\nexport async function createTestClient(\n schema: SchemaDef | string,\n options?: CreateTestClientOptions<SchemaDef>,\n): Promise<any> {\n let workDir = options?.workDir;\n let _schema: SchemaDef;\n const provider = options?.provider ?? getTestDbProvider() ?? 'sqlite';\n const dbName = options?.dbName ?? getTestDbName(provider);\n const dbUrl = provider === 'sqlite' ? `file:${dbName}` : `${TEST_PG_URL}/${dbName}`;\n\n let model: Model | undefined;\n\n if (typeof schema === 'string') {\n const generated = await generateTsSchema(schema, provider, dbUrl, options?.extraSourceFiles, undefined);\n workDir = generated.workDir;\n model = generated.model;\n // replace schema's provider\n _schema = {\n ...generated.schema,\n provider: {\n ...generated.schema.provider,\n type: provider,\n },\n } as SchemaDef;\n } else {\n // replace schema's provider\n _schema = {\n ...schema,\n provider: {\n type: provider,\n },\n };\n workDir ??= createTestProject();\n if (options?.schemaFile) {\n let schemaContent = fs.readFileSync(options.schemaFile, 'utf-8');\n if (dbUrl) {\n // replace `datasource db { }` section\n schemaContent = schemaContent.replace(\n /datasource\\s+db\\s*{[^}]*}/m,\n `datasource db {\n provider = '${provider}'\n url = '${dbUrl}'\n ${options.dataSourceExtensions ? `extensions = [${options.dataSourceExtensions.join(', ')}]` : ''}\n}`,\n );\n }\n fs.writeFileSync(path.join(workDir!, 'schema.zmodel'), schemaContent);\n }\n }\n\n invariant(workDir);\n\n const { plugins, ...rest } = options ?? {};\n const _options = {\n ...rest,\n } as ClientOptions<SchemaDef>;\n\n if (options?.debug) {\n console.log(`Work directory: ${workDir}`);\n console.log(`Database name: ${dbName}`);\n _options.log = testLogger;\n }\n\n // copy db file to workDir if specified\n if (options?.dbFile) {\n if (provider !== 'sqlite') {\n throw new Error('dbFile option is only supported for sqlite provider');\n }\n fs.copyFileSync(options.dbFile, path.join(workDir, dbName));\n }\n\n // copy additional files if specified\n if (options?.copyFiles) {\n const state = expect.getState();\n const currentTestPath = state.testPath;\n if (!currentTestPath) {\n throw new Error('Unable to determine current test file path');\n }\n for (const { globPattern, destination } of options.copyFiles) {\n const files = glob.sync(globPattern, { cwd: path.dirname(currentTestPath) });\n for (const file of files) {\n const src = path.resolve(path.dirname(currentTestPath), file);\n const dest = path.resolve(workDir, destination, path.basename(file));\n fs.mkdirSync(path.dirname(dest), { recursive: true });\n fs.copyFileSync(src, dest);\n }\n }\n }\n\n if (!options?.dbFile) {\n if (options?.usePrismaPush) {\n invariant(\n typeof schema === 'string' || options?.schemaFile,\n 'a schema file must be provided when using prisma db push',\n );\n if (!model) {\n const r = await loadDocumentWithPlugins(path.join(workDir, 'schema.zmodel'));\n if (!r.success) {\n throw new Error(r.errors.join('\\n'));\n }\n model = r.model;\n }\n const prismaSchema = new PrismaSchemaGenerator(model);\n const prismaSchemaText = await prismaSchema.generate();\n fs.writeFileSync(path.resolve(workDir!, 'schema.prisma'), prismaSchemaText);\n execSync('npx prisma db push --schema ./schema.prisma --skip-generate --force-reset', {\n cwd: workDir,\n stdio: 'ignore',\n });\n } else {\n if (provider === 'postgresql') {\n invariant(dbName, 'dbName is required');\n const pgClient = new PGClient(TEST_PG_CONFIG);\n await pgClient.connect();\n await pgClient.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n await pgClient.query(`CREATE DATABASE \"${dbName}\"`);\n await pgClient.end();\n }\n }\n }\n\n if (provider === 'postgresql') {\n _options.dialect = new PostgresDialect({\n pool: new Pool({\n ...TEST_PG_CONFIG,\n database: dbName,\n }),\n });\n } else {\n _options.dialect = new SqliteDialect({\n database: new SQLite(path.join(workDir!, dbName)),\n });\n }\n\n let client = new ZenStackClient(_schema, _options);\n\n if (!options?.usePrismaPush && !options?.dbFile) {\n await client.$pushSchema();\n }\n\n if (plugins) {\n for (const plugin of plugins) {\n client = client.$use(plugin);\n }\n }\n\n return client;\n}\n\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema,\n options?: CreateTestClientOptions<Schema>,\n): Promise<ClientContract<Schema>>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any>;\nexport async function createPolicyTestClient<Schema extends SchemaDef>(\n schema: Schema | string,\n options?: CreateTestClientOptions<Schema>,\n): Promise<any> {\n return createTestClient(\n schema as any,\n {\n ...options,\n plugins: [...(options?.plugins ?? []), new PolicyPlugin()],\n } as any,\n );\n}\n\nexport function testLogger(e: LogEvent) {\n console.log(e.query.sql, e.query.parameters);\n}\n\nfunction getTestDbName(provider: string) {\n if (provider === 'sqlite') {\n return './test.db';\n }\n const testName = expect.getState().currentTestName ?? 'unnamed';\n const testPath = expect.getState().testPath ?? '';\n // digest test name\n const digest = createHash('md5')\n .update(testName + testPath)\n .digest('hex');\n // compute a database name based on test name\n return (\n 'test_' +\n testName\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, '_')\n .replace(/_+/g, '_')\n .substring(0, 30) +\n digest.slice(0, 6)\n );\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport tmp from 'tmp';\n\nexport function createTestProject(zmodelContent?: string) {\n const { name: workDir } = tmp.dirSync({ unsafeCleanup: true });\n\n fs.mkdirSync(path.join(workDir, 'node_modules'));\n\n // symlink all entries from \"node_modules\"\n const nodeModules = fs.readdirSync(path.join(__dirname, '../node_modules'));\n for (const entry of nodeModules) {\n if (entry.startsWith('@zenstackhq')) {\n continue;\n }\n fs.symlinkSync(\n path.join(__dirname, '../node_modules', entry),\n path.join(workDir, 'node_modules', entry),\n 'dir',\n );\n }\n\n // in addition, symlink zenstack packages\n const zenstackPackages = ['language', 'sdk', 'orm', 'cli'];\n fs.mkdirSync(path.join(workDir, 'node_modules/@zenstackhq'));\n for (const pkg of zenstackPackages) {\n fs.symlinkSync(\n path.join(__dirname, `../../${pkg}`),\n path.join(workDir, `node_modules/@zenstackhq/${pkg}`),\n 'dir',\n );\n }\n\n fs.writeFileSync(\n path.join(workDir, 'package.json'),\n JSON.stringify(\n {\n name: 'test',\n version: '1.0.0',\n type: 'module',\n },\n null,\n 4,\n ),\n );\n\n fs.writeFileSync(\n path.join(workDir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n module: 'ESNext',\n target: 'ESNext',\n moduleResolution: 'Bundler',\n esModuleInterop: true,\n skipLibCheck: true,\n strict: true,\n },\n include: ['**/*.ts'],\n },\n null,\n 4,\n ),\n );\n\n if (zmodelContent) {\n fs.writeFileSync(path.join(workDir, 'schema.zmodel'), zmodelContent);\n }\n\n return workDir;\n}\n","import { invariant } from '@zenstackhq/common-helpers';\nimport type { SchemaDef } from '@zenstackhq/schema';\nimport { TsSchemaGenerator } from '@zenstackhq/sdk';\nimport { execSync } from 'node:child_process';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { match } from 'ts-pattern';\nimport { expect } from 'vitest';\nimport { createTestProject } from './project';\nimport { loadDocumentWithPlugins } from './utils';\n\nfunction makePrelude(provider: 'sqlite' | 'postgresql', dbUrl?: string) {\n return match(provider)\n .with('sqlite', () => {\n return `\ndatasource db {\n provider = 'sqlite'\n url = '${dbUrl ?? 'file:./test.db'}'\n}\n`;\n })\n .with('postgresql', () => {\n return `\ndatasource db {\n provider = 'postgresql'\n url = '${dbUrl ?? 'postgres://postgres:postgres@localhost:5432/db'}'\n}\n`;\n })\n .exhaustive();\n}\n\nfunction replacePlaceholders(schemaText: string, provider: 'sqlite' | 'postgresql', dbUrl: string | undefined) {\n const url = dbUrl ?? (provider === 'sqlite' ? 'file:./test.db' : 'postgres://postgres:postgres@localhost:5432/db');\n return schemaText.replace(/\\$DB_URL/g, url).replace(/\\$PROVIDER/g, provider);\n}\n\nexport async function generateTsSchema(\n schemaText: string,\n provider: 'sqlite' | 'postgresql' = 'sqlite',\n dbUrl?: string,\n extraSourceFiles?: Record<string, string>,\n withLiteSchema?: boolean,\n) {\n const workDir = createTestProject();\n\n const zmodelPath = path.join(workDir, 'schema.zmodel');\n const noPrelude = schemaText.includes('datasource ');\n fs.writeFileSync(\n zmodelPath,\n `${noPrelude ? '' : makePrelude(provider, dbUrl)}\\n\\n${replacePlaceholders(schemaText, provider, dbUrl)}`,\n );\n\n const result = await loadDocumentWithPlugins(zmodelPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${zmodelPath}: ${result.errors}`);\n }\n\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir, lite: withLiteSchema });\n\n if (extraSourceFiles) {\n for (const [fileName, content] of Object.entries(extraSourceFiles)) {\n const filePath = path.resolve(workDir, !fileName.endsWith('.ts') ? `${fileName}.ts` : fileName);\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, content);\n }\n }\n\n // compile the generated TS schema\n return { ...(await compileAndLoad(workDir)), model: result.model };\n}\n\nasync function compileAndLoad(workDir: string) {\n execSync('npx tsc', {\n cwd: workDir,\n stdio: 'inherit',\n });\n\n // load the schema module\n const module = await import(path.join(workDir, 'schema.js'));\n\n let moduleLite: any;\n try {\n moduleLite = await import(path.join(workDir, 'schema-lite.js'));\n } catch {\n // ignore\n }\n return { workDir, schema: module.schema as SchemaDef, schemaLite: moduleLite?.schema as SchemaDef | undefined };\n}\n\nexport function generateTsSchemaFromFile(filePath: string) {\n const schemaText = fs.readFileSync(filePath, 'utf8');\n return generateTsSchema(schemaText);\n}\n\nexport async function generateTsSchemaInPlace(schemaPath: string) {\n const workDir = path.dirname(schemaPath);\n const result = await loadDocumentWithPlugins(schemaPath);\n if (!result.success) {\n throw new Error(`Failed to load schema from ${schemaPath}: ${result.errors}`);\n }\n const generator = new TsSchemaGenerator();\n await generator.generate(result.model, { outDir: workDir });\n return compileAndLoad(workDir);\n}\n\nexport async function loadSchema(schema: string, additionalSchemas?: Record<string, string>) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp folder\n const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zenstack-schema'));\n\n // create a temp file\n const tempFile = path.join(tempDir, `schema.zmodel`);\n fs.writeFileSync(tempFile, schema);\n\n if (additionalSchemas) {\n for (const [fileName, content] of Object.entries(additionalSchemas)) {\n let name = fileName;\n if (!name.endsWith('.zmodel')) {\n name += '.zmodel';\n }\n const filePath = path.join(tempDir, name);\n fs.writeFileSync(filePath, content);\n }\n }\n\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r).toSatisfy(\n (r) => r.success,\n `Failed to load schema: ${(r as any).errors?.map((e: any) => e.toString()).join(', ')}`,\n );\n invariant(r.success);\n return r.model;\n}\n\nexport async function loadSchemaWithError(schema: string, error: string | RegExp) {\n if (!schema.includes('datasource ')) {\n schema = `${makePrelude('sqlite')}\\n\\n${schema}`;\n }\n\n // create a temp file\n const tempFile = path.join(os.tmpdir(), `zenstack-schema-${crypto.randomUUID()}.zmodel`);\n fs.writeFileSync(tempFile, schema);\n const r = await loadDocumentWithPlugins(tempFile);\n expect(r.success).toBe(false);\n invariant(!r.success);\n if (typeof error === 'string') {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => e.toString().toLowerCase().includes(error.toLowerCase())),\n `Expected error message to include \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n } else {\n expect(r).toSatisfy(\n (r) => r.errors.some((e: any) => error.test(e)),\n `Expected error message to match \"${error}\" but got: ${r.errors.map((e: any) => e.toString()).join(', ')}`,\n );\n }\n}\n","import { loadDocument } from '@zenstackhq/language';\n\nexport function loadDocumentWithPlugins(filePath: string) {\n const pluginModelFiles = [require.resolve('@zenstackhq/plugin-policy/plugin.zmodel')];\n return loadDocument(filePath, pluginModelFiles);\n}\n","import { ORMError, ORMErrorReason } from '@zenstackhq/orm';\nimport { expect } from 'vitest';\n\nfunction isPromise(value: any) {\n return typeof value.then === 'function' && typeof value.catch === 'function';\n}\n\nfunction expectErrorReason(err: any, errorReason: ORMErrorReason) {\n if (err instanceof ORMError && err.reason === errorReason) {\n return {\n message: () => '',\n pass: true,\n };\n } else {\n return {\n message: () => `expected ORMError of reason ${errorReason}, got ${err}`,\n pass: false,\n };\n }\n}\n\nfunction expectErrorMessages(expectedMessages: string[], message: string) {\n for (const m of expectedMessages) {\n if (!message.toLowerCase().includes(m.toLowerCase())) {\n return {\n message: () => `expected message not found in error: ${m}, got message: ${message}`,\n pass: false,\n };\n }\n }\n return undefined;\n}\n\nexpect.extend({\n async toResolveTruthy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !!r,\n message: () => `Expected promise to resolve to a truthy value, but got ${r}`,\n };\n },\n\n async toResolveFalsy(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: !r,\n message: () => `Expected promise to resolve to a falsy value, but got ${r}`,\n };\n },\n\n async toResolveNull(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n const r = await received;\n return {\n pass: r === null,\n message: () => `Expected promise to resolve to a null value, but got ${r}`,\n };\n },\n\n async toResolveWithLength(received: Promise<unknown>, length: number) {\n const r = await received;\n return {\n pass: Array.isArray(r) && r.length === length,\n message: () => `Expected promise to resolve with an array with length ${length}, but got ${r}`,\n };\n },\n\n async toBeRejectedNotFound(received: Promise<unknown>) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n return expectErrorReason(err, ORMErrorReason.NOT_FOUND);\n }\n return {\n message: () => `expected NotFoundError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByPolicy(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.REJECTED_BY_POLICY) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.REJECTED_BY_POLICY);\n }\n return {\n message: () => `expected PolicyError, got no error`,\n pass: false,\n };\n },\n\n async toBeRejectedByValidation(received: Promise<unknown>, expectedMessages?: string[]) {\n if (!isPromise(received)) {\n return { message: () => 'a promise is expected', pass: false };\n }\n try {\n await received;\n } catch (err) {\n if (expectedMessages && err instanceof ORMError && err.reason === ORMErrorReason.INVALID_INPUT) {\n const r = expectErrorMessages(expectedMessages, err.message || '');\n if (r) {\n return r;\n }\n }\n return expectErrorReason(err, ORMErrorReason.INVALID_INPUT);\n }\n return {\n message: () => `expected InputValidationError, got no error`,\n pass: false,\n };\n },\n});\n"],"mappings":"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","names":["import_common_helpers","import_sdk","import_node_child_process","import_node_crypto","import_node_fs","import_node_path","import_vitest","createTestProject","zmodelContent","name","workDir","tmp","dirSync","unsafeCleanup","fs","mkdirSync","path","join","nodeModules","readdirSync","__dirname","entry","startsWith","symlinkSync","zenstackPackages","pkg","writeFileSync","JSON","stringify","version","type","compilerOptions","module","target","moduleResolution","esModuleInterop","skipLibCheck","strict","include","import_node_fs","import_node_path","loadDocumentWithPlugins","filePath","pluginModelFiles","require","loadDocument","makePrelude","provider","dbUrl","match","with","exhaustive","replacePlaceholders","schemaText","url","replace","generateTsSchema","extraSourceFiles","withLiteSchema","workDir","createTestProject","zmodelPath","path","join","noPrelude","includes","fs","writeFileSync","result","loadDocumentWithPlugins","success","Error","errors","generator","TsSchemaGenerator","generate","model","outDir","lite","fileName","content","Object","entries","filePath","resolve","endsWith","mkdirSync","dirname","recursive","compileAndLoad","execSync","cwd","stdio","module","moduleLite","schema","schemaLite","generateTsSchemaFromFile","readFileSync","generateTsSchemaInPlace","schemaPath","loadSchema","additionalSchemas","tempDir","mkdtempSync","os","tmpdir","tempFile","name","r","expect","toSatisfy","map","e","toString","invariant","loadSchemaWithError","error","crypto","randomUUID","toBe","some","toLowerCase","test","getTestDbProvider","val","process","env","includes","Error","TEST_PG_CONFIG","host","port","parseInt","user","password","TEST_PG_URL","createTestClient","schema","options","workDir","_schema","provider","dbName","getTestDbName","dbUrl","model","generated","generateTsSchema","extraSourceFiles","undefined","type","createTestProject","schemaFile","schemaContent","fs","readFileSync","replace","dataSourceExtensions","join","writeFileSync","path","invariant","plugins","rest","_options","debug","console","log","testLogger","dbFile","copyFileSync","copyFiles","state","expect","getState","currentTestPath","testPath","globPattern","destination","files","glob","sync","cwd","dirname","file","src","resolve","dest","basename","mkdirSync","recursive","usePrismaPush","r","loadDocumentWithPlugins","success","errors","prismaSchema","PrismaSchemaGenerator","prismaSchemaText","generate","execSync","stdio","pgClient","PGClient","connect","query","end","dialect","PostgresDialect","pool","Pool","database","SqliteDialect","SQLite","client","ZenStackClient","$pushSchema","plugin","$use","createPolicyTestClient","PolicyPlugin","e","sql","parameters","testName","currentTestName","digest","createHash","update","toLowerCase","substring","slice","import_orm","import_vitest","isPromise","value","then","catch","expectErrorReason","err","errorReason","ORMError","reason","message","pass","expectErrorMessages","expectedMessages","m","toLowerCase","includes","undefined","expect","extend","toResolveTruthy","received","r","toResolveFalsy","toResolveNull","toResolveWithLength","length","Array","isArray","toBeRejectedNotFound","ORMErrorReason","NOT_FOUND","toBeRejectedByPolicy","REJECTED_BY_POLICY","toBeRejectedByValidation","INVALID_INPUT"]}