@suss/packs 0.34.0 → 0.35.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/prisma.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  } from "ts-morph";
7
7
  import { z } from "zod";
8
8
  import { receiverTypesOf, writtenNodeOf } from "@suss/adapter-typescript";
9
- import { storageBinding } from "@suss/behavioral-ir";
9
+ import { storageBinding as storageBinding2 } from "@suss/behavioral-ir";
10
10
  import { scopeOption, storageSystemOption } from "@suss/extractor";
11
11
  import {
12
12
  compile,
@@ -14,10 +14,95 @@ import {
14
14
  declaredBy,
15
15
  sqlStatements
16
16
  } from "@suss/recognize";
17
+ import fs3 from "fs";
18
+ import path3 from "path";
19
+ import { getSchema as getSchema2 } from "@mrleebo/prisma-ast";
20
+ import { ts } from "ts-morph";
21
+
22
+ // ../contract/prisma/dist/index.js
17
23
  import fs from "fs";
18
24
  import path from "path";
19
25
  import { getSchema } from "@mrleebo/prisma-ast";
20
- import { ts } from "ts-morph";
26
+ import { storageBinding } from "@suss/behavioral-ir";
27
+ import { defaultProjectRoot, pathInProject } from "@suss/behavioral-ir/files";
28
+ var PROVIDER_TO_SYSTEM = {
29
+ postgresql: "postgresql",
30
+ postgres: "postgresql",
31
+ mysql: "mysql",
32
+ sqlite: "sqlite"
33
+ };
34
+ function prismaSchemaFiles(schemaPath) {
35
+ const stat = statOf(schemaPath);
36
+ if (stat?.isDirectory() === true) {
37
+ return prismaFilesIn(schemaPath, true);
38
+ }
39
+ if (stat?.isFile() !== true) {
40
+ return [];
41
+ }
42
+ const beside = prismaFilesIn(path.dirname(schemaPath), false).flatMap(
43
+ (file) => {
44
+ const list = schemaListOf(file);
45
+ return list === null ? [] : [{ file, list }];
46
+ }
47
+ );
48
+ const datasources = beside.filter(
49
+ ({ list }) => list.some(isDatasource)
50
+ ).length;
51
+ const given = path.resolve(schemaPath);
52
+ return datasources === 1 && beside.some(({ file }) => path.resolve(file) === given) ? beside.map(({ file }) => file) : [schemaPath];
53
+ }
54
+ function statOf(file) {
55
+ try {
56
+ return fs.statSync(file);
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+ function prismaFilesIn(dir, below) {
62
+ return fs.readdirSync(dir, { recursive: below, encoding: "utf8" }).filter((name) => name.endsWith(".prisma")).map((name) => path.join(dir, name)).filter((file) => statOf(file)?.isFile() === true).sort();
63
+ }
64
+ function schemaListOf(file) {
65
+ try {
66
+ return getSchema(fs.readFileSync(file, "utf8")).list;
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+ function isDatasource(node) {
72
+ return node.type === "datasource";
73
+ }
74
+ function prismaStorageSystem(source) {
75
+ try {
76
+ return storageSystemIn(getSchema(source).list);
77
+ } catch {
78
+ return null;
79
+ }
80
+ }
81
+ function storageSystemIn(list) {
82
+ for (const node of list) {
83
+ if (node.type !== "datasource") {
84
+ continue;
85
+ }
86
+ const provider = readProviderString(node);
87
+ if (provider !== null && provider in PROVIDER_TO_SYSTEM) {
88
+ return PROVIDER_TO_SYSTEM[provider];
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+ function readProviderString(ds) {
94
+ for (const a of ds.assignments) {
95
+ if (a.key !== "provider") {
96
+ continue;
97
+ }
98
+ if (typeof a.value === "string") {
99
+ return a.value.replace(/^"|"$/g, "");
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+
105
+ // ../framework/prisma/dist/index.js
21
106
  var CONFIG_FILES = [
22
107
  "prisma.config.ts",
23
108
  "prisma.config.mts",
@@ -25,43 +110,61 @@ var CONFIG_FILES = [
25
110
  "prisma.config.js",
26
111
  "prisma.config.mjs",
27
112
  "prisma.config.cjs",
28
- path.join(".config", "prisma.ts")
113
+ path3.join(".config", "prisma.ts")
29
114
  ];
30
- var DEFAULT_SCHEMAS = [path.join("prisma", "schema.prisma"), "schema.prisma"];
115
+ var DEFAULT_SCHEMAS = [path3.join("prisma", "schema.prisma"), "schema.prisma"];
31
116
  var readProjects = /* @__PURE__ */ new Map();
32
117
  function generatedClientDirs(fromDir) {
118
+ return readProjectAt(fromDir)?.dirs ?? [];
119
+ }
120
+ function schemaStorageSystem(fromDir) {
121
+ return readProjectAt(fromDir)?.storageSystem ?? null;
122
+ }
123
+ function readProjectAt(fromDir) {
33
124
  const root = projectRootOf(fromDir);
34
125
  if (root === null) {
35
- return [];
126
+ return null;
36
127
  }
37
128
  const known = readProjects.get(root);
38
129
  if (known !== void 0 && unchanged(known.readFrom)) {
39
- return known.dirs;
130
+ return known;
40
131
  }
41
132
  const schemaFiles = schemaFilesOf(root);
42
133
  const readFrom = /* @__PURE__ */ new Map();
43
134
  for (const file of [...projectFilesOf(root), ...schemaFiles]) {
44
135
  readFrom.set(file, changedAt(file));
45
136
  }
46
- const dirs = schemaFiles.flatMap(outputDirsIn);
47
- readProjects.set(root, { dirs, readFrom });
48
- return dirs;
137
+ const sources = schemaFiles.map((file) => ({ file, text: textOf(file) }));
138
+ const project = {
139
+ dirs: sources.flatMap(outputDirsIn),
140
+ storageSystem: sources.map(({ text }) => prismaStorageSystem(text)).find((system) => system !== null) ?? null,
141
+ readFrom
142
+ };
143
+ readProjects.set(root, project);
144
+ return project;
145
+ }
146
+ function textOf(file) {
147
+ try {
148
+ return fs3.readFileSync(file, "utf8");
149
+ } catch {
150
+ return "";
151
+ }
49
152
  }
50
153
  function isInGeneratedClient(filePath) {
51
- return generatedClientDirs(path.dirname(filePath)).some(
52
- (dir) => filePath.startsWith(`${dir}${path.sep}`)
154
+ return generatedClientDirs(path3.dirname(filePath)).some(
155
+ (dir) => filePath.startsWith(`${dir}${path3.sep}`)
53
156
  );
54
157
  }
55
158
  function projectFilesOf(root) {
56
159
  return [
57
- path.join(root, "package.json"),
58
- ...CONFIG_FILES.map((name) => path.join(root, name)),
59
- ...DEFAULT_SCHEMAS.map((name) => path.join(root, name))
160
+ path3.join(root, "package.json"),
161
+ ...CONFIG_FILES.map((name) => path3.join(root, name)),
162
+ ...DEFAULT_SCHEMAS.map((name) => path3.join(root, name))
60
163
  ];
61
164
  }
62
165
  function changedAt(file) {
63
166
  try {
64
- return fs.statSync(file).mtimeMs;
167
+ return fs3.statSync(file).mtimeMs;
65
168
  } catch {
66
169
  return -1;
67
170
  }
@@ -85,12 +188,12 @@ function projectRootOf(fromDir) {
85
188
  return root;
86
189
  }
87
190
  function findProjectRoot(fromDir) {
88
- let dir = path.resolve(fromDir);
191
+ let dir = path3.resolve(fromDir);
89
192
  while (true) {
90
- if (fs.existsSync(path.join(dir, "package.json")) || configFileIn(dir) !== null) {
193
+ if (fs3.existsSync(path3.join(dir, "package.json")) || configFileIn(dir) !== null) {
91
194
  return dir;
92
195
  }
93
- const parent = path.dirname(dir);
196
+ const parent = path3.dirname(dir);
94
197
  if (parent === dir) {
95
198
  return null;
96
199
  }
@@ -99,41 +202,31 @@ function findProjectRoot(fromDir) {
99
202
  }
100
203
  function configFileIn(dir) {
101
204
  for (const name of CONFIG_FILES) {
102
- const candidate = path.join(dir, name);
103
- if (fs.existsSync(candidate)) {
205
+ const candidate = path3.join(dir, name);
206
+ if (fs3.existsSync(candidate)) {
104
207
  return candidate;
105
208
  }
106
209
  }
107
210
  return null;
108
211
  }
109
212
  function schemaFilesOf(root) {
110
- const stated = [configuredSchema(root), packageJsonSchema(root)];
213
+ const manifest = manifestOf(root);
214
+ const stated = [
215
+ configuredSchema(root),
216
+ packageJsonSchema(root, manifest),
217
+ generateScriptSchema(root, manifest)
218
+ ];
111
219
  for (const schema of [
112
220
  ...stated.filter((one) => one !== null),
113
- ...DEFAULT_SCHEMAS.map((name) => path.join(root, name))
221
+ ...DEFAULT_SCHEMAS.map((name) => path3.join(root, name))
114
222
  ]) {
115
- const files = prismaFilesAt(schema);
223
+ const files = prismaSchemaFiles(schema);
116
224
  if (files.length > 0) {
117
225
  return files;
118
226
  }
119
227
  }
120
228
  return [];
121
229
  }
122
- function prismaFilesAt(schemaPath) {
123
- let stat;
124
- try {
125
- stat = fs.statSync(schemaPath);
126
- } catch {
127
- return [];
128
- }
129
- if (stat.isFile()) {
130
- return [schemaPath];
131
- }
132
- if (!stat.isDirectory()) {
133
- return [];
134
- }
135
- return fs.readdirSync(schemaPath, { recursive: true, encoding: "utf8" }).filter((name) => name.endsWith(".prisma")).map((name) => path.join(schemaPath, name)).sort();
136
- }
137
230
  function configuredSchema(root) {
138
231
  const config = configFileIn(root);
139
232
  if (config === null) {
@@ -141,7 +234,7 @@ function configuredSchema(root) {
141
234
  }
142
235
  const source = ts.createSourceFile(
143
236
  config,
144
- fs.readFileSync(config, "utf8"),
237
+ fs3.readFileSync(config, "utf8"),
145
238
  ts.ScriptTarget.Latest
146
239
  );
147
240
  let found = null;
@@ -156,25 +249,36 @@ function configuredSchema(root) {
156
249
  ts.forEachChild(node, visit);
157
250
  };
158
251
  visit(source);
159
- return found === null ? null : path.resolve(root, found);
252
+ return found === null ? null : path3.resolve(root, found);
160
253
  }
161
- function packageJsonSchema(root) {
162
- const file = path.join(root, "package.json");
163
- if (!fs.existsSync(file)) {
164
- return null;
165
- }
254
+ function manifestOf(root) {
166
255
  try {
167
- const manifest = JSON.parse(fs.readFileSync(file, "utf8"));
168
- const schema = manifest.prisma?.schema;
169
- return typeof schema === "string" ? path.resolve(root, schema) : null;
256
+ return JSON.parse(
257
+ fs3.readFileSync(path3.join(root, "package.json"), "utf8")
258
+ );
170
259
  } catch {
171
260
  return null;
172
261
  }
173
262
  }
174
- function outputDirsIn(schemaFile) {
263
+ function packageJsonSchema(root, manifest) {
264
+ const schema = manifest?.prisma?.schema;
265
+ return typeof schema === "string" ? path3.resolve(root, schema) : null;
266
+ }
267
+ var GENERATE_SCHEMA_FLAG = /\bprisma\s+generate\b[^&|;]*?--schema(?:=|\s+)(["']?)([^\s"'&|;]+)\1/;
268
+ function generateScriptSchema(root, manifest) {
269
+ for (const script of Object.values(manifest?.scripts ?? {})) {
270
+ const match = typeof script === "string" ? GENERATE_SCHEMA_FLAG.exec(script) : null;
271
+ if (match?.[2] !== void 0) {
272
+ return path3.resolve(root, match[2]);
273
+ }
274
+ }
275
+ return null;
276
+ }
277
+ function outputDirsIn(schema) {
278
+ const schemaFile = schema.file;
175
279
  let list;
176
280
  try {
177
- list = getSchema(fs.readFileSync(schemaFile, "utf8")).list;
281
+ list = getSchema2(schema.text).list;
178
282
  } catch {
179
283
  return [];
180
284
  }
@@ -182,7 +286,7 @@ function outputDirsIn(schemaFile) {
182
286
  for (const block of list) {
183
287
  const output = generatorOutput(block);
184
288
  if (output !== null) {
185
- dirs.push(path.resolve(path.dirname(schemaFile), output));
289
+ dirs.push(path3.resolve(path3.dirname(schemaFile), output));
186
290
  }
187
291
  }
188
292
  return dirs;
@@ -219,9 +323,9 @@ var PRISMA_WRITE_METHODS = /* @__PURE__ */ new Set([
219
323
  ]);
220
324
  var optionsSchema = z.object({
221
325
  /**
222
- * The storage system the calls target, `"postgresql"` when unset. It
223
- * has to match the `storageSystem` on the schema reader's summaries,
224
- * or the calls do not pair.
326
+ * The storage system the calls target. When unset, the project
327
+ * schema's datasource decides, then `"postgresql"`. The README says
328
+ * why it has to match the schema reader's summaries.
225
329
  */
226
330
  storageSystem: storageSystemOption.optional(),
227
331
  /**
@@ -231,10 +335,18 @@ var optionsSchema = z.object({
231
335
  scope: scopeOption.optional()
232
336
  }).strict();
233
337
  function makeRecognizer(opts) {
234
- const storageSystem = opts.storageSystem ?? "postgresql";
235
338
  const scope = opts.scope ?? "default";
236
- return (call, ctx) => recognizePrismaCall(call, ctx, storageSystem, scope);
339
+ return (call, ctx) => recognizePrismaCall(
340
+ call,
341
+ ctx,
342
+ storageSystemFor(opts, call.getSourceFile()),
343
+ scope
344
+ );
345
+ }
346
+ function storageSystemFor(opts, file) {
347
+ return opts.storageSystem ?? schemaStorageSystem(path2.dirname(file.getFilePath())) ?? DEFAULT_STORAGE_SYSTEM;
237
348
  }
349
+ var DEFAULT_STORAGE_SYSTEM = "postgresql";
238
350
  function recognizePrismaCall(call, ctx, storageSystem, scope) {
239
351
  const callNode = call;
240
352
  const recognizerCtx = ctx;
@@ -266,7 +378,7 @@ function recognizePrismaCall(call, ctx, storageSystem, scope) {
266
378
  const optionsArg = readObjectArg(argsShape[0]);
267
379
  const fields = extractFields(optionsArg, kind);
268
380
  const selector = extractSelector(optionsArg);
269
- const binding = storageBinding({
381
+ const binding = storageBinding2({
270
382
  recognition: "@suss/framework-prisma",
271
383
  storageSystem,
272
384
  scope,
@@ -352,7 +464,7 @@ function nestedReads(optionsArg) {
352
464
  collectRelations(optionsArg, [], found);
353
465
  return found;
354
466
  }
355
- function collectRelations(shape, path3, found) {
467
+ function collectRelations(shape, path32, found) {
356
468
  const select = readObjectArg(shape.fields.select);
357
469
  if (select !== null) {
358
470
  for (const [name, value] of Object.entries(select.fields)) {
@@ -360,7 +472,7 @@ function collectRelations(shape, path3, found) {
360
472
  if (nested === null) {
361
473
  continue;
362
474
  }
363
- recordRelation(name, nested, path3, found);
475
+ recordRelation(name, nested, path32, found);
364
476
  }
365
477
  }
366
478
  const include = readObjectArg(shape.fields.include);
@@ -370,14 +482,14 @@ function collectRelations(shape, path3, found) {
370
482
  for (const [name, value] of Object.entries(include.fields)) {
371
483
  const nested = readObjectArg(value);
372
484
  if (nested === null) {
373
- found.push({ relationPath: [...path3, name], fields: ["*"] });
485
+ found.push({ relationPath: [...path32, name], fields: ["*"] });
374
486
  continue;
375
487
  }
376
- recordRelation(name, nested, path3, found);
488
+ recordRelation(name, nested, path32, found);
377
489
  }
378
490
  }
379
- function recordRelation(name, nested, path3, found) {
380
- const relationPath = [...path3, name];
491
+ function recordRelation(name, nested, path32, found) {
492
+ const relationPath = [...path32, name];
381
493
  found.push({ relationPath, fields: extractFields(nested, "read") });
382
494
  collectRelations(nested, relationPath, found);
383
495
  }
@@ -431,13 +543,13 @@ function nestedWrites(optionsArg) {
431
543
  }
432
544
  return found;
433
545
  }
434
- function collectNestedWrites(row, path3, found) {
546
+ function collectNestedWrites(row, path32, found) {
435
547
  for (const [field, value] of Object.entries(row.fields)) {
436
548
  const nested = readObjectArg(value);
437
549
  if (nested === null) {
438
550
  continue;
439
551
  }
440
- const relationPath = [...path3, field];
552
+ const relationPath = [...path32, field];
441
553
  for (const [operation, payload] of Object.entries(nested.fields)) {
442
554
  const does = NESTED_OPERATIONS.get(operation);
443
555
  if (does === void 0) {
@@ -614,8 +726,7 @@ function extractSelector(optionsArg) {
614
726
  return keys.length > 0 ? keys : null;
615
727
  }
616
728
  var STATEMENT = { statement: { at: 0 } };
617
- function rawStatements(options) {
618
- const provider = options.storageSystem ?? "postgresql";
729
+ function rawStatements(options, provider) {
619
730
  return sqlStatements({
620
731
  system: provider,
621
732
  dialect: provider,
@@ -628,8 +739,26 @@ function rawStatements(options) {
628
739
  $executeRawUnsafe: STATEMENT
629
740
  }).example('prisma.$queryRawUnsafe("SELECT id, email FROM users")');
630
741
  }
742
+ function rawRecognizer(options) {
743
+ const bySystem = /* @__PURE__ */ new Map();
744
+ return (call, ctx) => {
745
+ const system = storageSystemFor(options, call.getSourceFile());
746
+ let recognizer = bySystem.get(system);
747
+ if (recognizer === void 0) {
748
+ recognizer = compile(
749
+ rawStatements(options, system).declared,
750
+ "@suss/framework-prisma"
751
+ );
752
+ bySystem.set(system, recognizer);
753
+ }
754
+ return recognizer(call, ctx);
755
+ };
756
+ }
631
757
  function prismaFramework(options = {}) {
632
- const raw = rawStatements(options);
758
+ const raw = rawStatements(
759
+ options,
760
+ options.storageSystem ?? DEFAULT_STORAGE_SYSTEM
761
+ );
633
762
  return {
634
763
  name: "prisma",
635
764
  protocol: "in-process",
@@ -648,7 +777,7 @@ function prismaFramework(options = {}) {
648
777
  invocationRecognizers: [makeRecognizer(options)],
649
778
  // A tagged template is not an invocation, so the raw chain runs on
650
779
  // the access walk, which visits calls as well.
651
- accessRecognizers: [compile(raw.declared, "@suss/framework-prisma")],
780
+ accessRecognizers: [rawRecognizer(options)],
652
781
  declarations: declarationsIn([raw])
653
782
  };
654
783
  }