@aventara/prisma7-adapter 0.1.0-pilot.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/LICENSE +91 -0
- package/LICENSE-ADDITIONAL-PERMISSION.md +9 -0
- package/README.md +564 -0
- package/dist/discovery/artifact.loader.d.ts +26 -0
- package/dist/discovery/artifact.loader.js +124 -0
- package/dist/discovery/capability-surface.interface.d.ts +191 -0
- package/dist/discovery/capability-surface.interface.js +13 -0
- package/dist/discovery/capability.deriver.d.ts +92 -0
- package/dist/discovery/capability.deriver.js +350 -0
- package/dist/discovery/discovery-artifact.interface.d.ts +210 -0
- package/dist/discovery/discovery-artifact.interface.js +1 -0
- package/dist/discovery/enum.mapper.d.ts +59 -0
- package/dist/discovery/enum.mapper.js +32 -0
- package/dist/discovery/field.mapper.d.ts +244 -0
- package/dist/discovery/field.mapper.js +387 -0
- package/dist/discovery/identifier.mapper.d.ts +188 -0
- package/dist/discovery/identifier.mapper.js +132 -0
- package/dist/discovery/model.discoverer.d.ts +108 -0
- package/dist/discovery/model.discoverer.js +341 -0
- package/dist/discovery/operations.deriver.d.ts +75 -0
- package/dist/discovery/operations.deriver.js +92 -0
- package/dist/discovery/scalar.mapper.d.ts +81 -0
- package/dist/discovery/scalar.mapper.js +51 -0
- package/dist/discovery/schema-facts.interface.d.ts +174 -0
- package/dist/discovery/schema-facts.interface.js +11 -0
- package/dist/discovery/schema.reader.d.ts +162 -0
- package/dist/discovery/schema.reader.js +692 -0
- package/dist/discovery/types.reader.d.ts +24 -0
- package/dist/discovery/types.reader.js +617 -0
- package/dist/discovery/vocabulary.dictionary.d.ts +258 -0
- package/dist/discovery/vocabulary.dictionary.js +429 -0
- package/dist/errors/error.normalizer.d.ts +250 -0
- package/dist/errors/error.normalizer.js +135 -0
- package/dist/errors/prisma-error.reader.d.ts +144 -0
- package/dist/errors/prisma-error.reader.js +167 -0
- package/dist/execution/first-variant.emulator.d.ts +64 -0
- package/dist/execution/first-variant.emulator.js +205 -0
- package/dist/execution/operation.executor.d.ts +87 -0
- package/dist/execution/operation.executor.js +210 -0
- package/dist/execution/result.shaper.d.ts +103 -0
- package/dist/execution/result.shaper.js +141 -0
- package/dist/execution/transaction.executor.d.ts +147 -0
- package/dist/execution/transaction.executor.js +13 -0
- package/dist/generate/artifact.emitter.d.ts +50 -0
- package/dist/generate/artifact.emitter.js +105 -0
- package/dist/generate/declared-support.reader.d.ts +33 -0
- package/dist/generate/declared-support.reader.js +74 -0
- package/dist/generate/discovery.bin.d.ts +2 -0
- package/dist/generate/discovery.bin.js +15 -0
- package/dist/generate/discovery.cli.d.ts +24 -0
- package/dist/generate/discovery.cli.js +163 -0
- package/dist/generate/existence.gate.d.ts +73 -0
- package/dist/generate/existence.gate.js +91 -0
- package/dist/generate/index.d.ts +81 -0
- package/dist/generate/index.js +65 -0
- package/dist/generate/node-version.guard.d.ts +8 -0
- package/dist/generate/node-version.guard.js +59 -0
- package/dist/generate/prisma-cli.resolver.d.ts +48 -0
- package/dist/generate/prisma-cli.resolver.js +95 -0
- package/dist/generate/prisma.generate.d.ts +164 -0
- package/dist/generate/prisma.generate.js +278 -0
- package/dist/generate/reader-crosscheck.d.ts +156 -0
- package/dist/generate/reader-crosscheck.js +202 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -0
- package/dist/prisma-client.interface.d.ts +48 -0
- package/dist/prisma-client.interface.js +9 -0
- package/dist/prisma.adapter.d.ts +55 -0
- package/dist/prisma.adapter.js +105 -0
- package/dist/provider/provider-profile.d.ts +53 -0
- package/dist/provider/provider-profile.js +91 -0
- package/dist/translation/identifier.addressing.d.ts +80 -0
- package/dist/translation/identifier.addressing.js +30 -0
- package/dist/translation/mutation.translator.d.ts +115 -0
- package/dist/translation/mutation.translator.js +580 -0
- package/dist/translation/operation.translator.d.ts +273 -0
- package/dist/translation/operation.translator.js +377 -0
- package/dist/translation/order-pagination.translator.d.ts +86 -0
- package/dist/translation/order-pagination.translator.js +159 -0
- package/dist/translation/projection.translator.d.ts +115 -0
- package/dist/translation/projection.translator.js +151 -0
- package/dist/translation/scalar.conversion.d.ts +101 -0
- package/dist/translation/scalar.conversion.js +221 -0
- package/dist/translation/where.translator.d.ts +79 -0
- package/dist/translation/where.translator.js +254 -0
- package/package.json +102 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createPrismaModelComposer } from "../discovery/model.discoverer.js";
|
|
2
|
+
import { resolveProviderProfile } from "../provider/provider-profile.js";
|
|
3
|
+
import { runPrismaGenerateStep } from "./prisma.generate.js";
|
|
4
|
+
/**
|
|
5
|
+
* F-805 โ the package's **second published entry**: `@aventara/prisma7-adapter/generate`.
|
|
6
|
+
*
|
|
7
|
+
* # Why a second entry rather than a second package or a wider `"."`
|
|
8
|
+
*
|
|
9
|
+
* The runtime entry (`"."`) depends on `@aventara/core` and the caller's own
|
|
10
|
+
* generated client, and on nothing else. The generate path needs `typescript`
|
|
11
|
+
* (the types reader builds a real TypeScript program over the generated tree) and
|
|
12
|
+
* `prisma` (the step runs `prisma generate` itself, so that both sources describe
|
|
13
|
+
* one instant). Those two are declared as **optional peer dependencies**, not as
|
|
14
|
+
* dependencies, and the split is what keeps the plan's guarantee that *no
|
|
15
|
+
* compiler, no parser and no Prisma tooling enters the deployed runtime*: a
|
|
16
|
+
* consumer who imports only `"."` never loads a module that names either, and an
|
|
17
|
+
* optional peer is not installed on their behalf.
|
|
18
|
+
*
|
|
19
|
+
* The published build therefore carries both halves and the `exports` map is what
|
|
20
|
+
* separates them. Nothing reachable from `"."` imports anything under
|
|
21
|
+
* `generate/`; `artifact.loader.spec.ts` asserts that from the import graph
|
|
22
|
+
* rather than from this paragraph.
|
|
23
|
+
*
|
|
24
|
+
* # What this entry is for
|
|
25
|
+
*
|
|
26
|
+
* Producing the discovery artifact `createPrismaAdapter({ discovery })` requires,
|
|
27
|
+
* from the consumer's own `schema.prisma` and their own generated client. The
|
|
28
|
+
* `aventara-prisma7-generate` binary (`discovery.cli.ts`) is this function with an
|
|
29
|
+
* argument parser in front of it; this module is the same thing for a consumer who
|
|
30
|
+
* already has a build script and would rather call it.
|
|
31
|
+
*
|
|
32
|
+
* Everything the step itself exposes is re-exported, because the seams are the
|
|
33
|
+
* point: a consumer with an unusual toolchain can supply their own
|
|
34
|
+
* {@link PrismaGenerateToolchain}, and one with their own composition rules can
|
|
35
|
+
* call {@link runPrismaGenerateStep} directly.
|
|
36
|
+
*/
|
|
37
|
+
export { createPrismaModelComposer, PrismaModelCompositionError, } from "../discovery/model.discoverer.js";
|
|
38
|
+
export { createPrismaGenerateToolchain, PINNED_PRISMA_MAJOR, PrismaGenerateStepError, runPrismaGenerateStep, } from "./prisma.generate.js";
|
|
39
|
+
/**
|
|
40
|
+
* The generate step, wired: provider profile โ transaction capability โ
|
|
41
|
+
* composition โ the step.
|
|
42
|
+
*
|
|
43
|
+
* Every decision stays where it already lived. This function resolves the profile
|
|
44
|
+
* and builds the composer; it makes no judgement of its own, which is why there is
|
|
45
|
+
* nothing here to test beyond that it is the wiring the CLI and the repository's
|
|
46
|
+
* own `generate` script both use.
|
|
47
|
+
*/
|
|
48
|
+
export async function generatePrismaDiscoveryArtifact(request) {
|
|
49
|
+
const profile = resolveProviderProfile({
|
|
50
|
+
provider: request.provider,
|
|
51
|
+
driver: request.driver,
|
|
52
|
+
});
|
|
53
|
+
return runPrismaGenerateStep({
|
|
54
|
+
schema: request.schema,
|
|
55
|
+
clientDirectory: request.clientDirectory,
|
|
56
|
+
provider: request.provider,
|
|
57
|
+
artifactFile: request.artifactFile,
|
|
58
|
+
composeModel: createPrismaModelComposer({
|
|
59
|
+
transactions: profile.transactions,
|
|
60
|
+
}),
|
|
61
|
+
...(request.toolchain === undefined
|
|
62
|
+
? {}
|
|
63
|
+
: { toolchain: request.toolchain }),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The sentence a bin answers on `version`, or `undefined` when `range` admits it. */
|
|
2
|
+
export declare function nodeVersionRefusal(bin: string, packageName: string, range: string, version: string): string | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* Reads the manifest at `manifestUrl`; on a Node its `engines.node` does not
|
|
5
|
+
* admit, writes the sentence to stderr, sets exit code 1 and answers `true` โ
|
|
6
|
+
* the bin then loads nothing else.
|
|
7
|
+
*/
|
|
8
|
+
export declare function refuseUnsupportedNode(bin: string, manifestUrl: URL): boolean;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// biome-ignore lint/style/useNodejsImportProtocol: Node 14.0โ14.13.0 resolves no "node:" specifier in an ES module, and this module runs on the Nodes the packages do not support.
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
function versionOf(text) {
|
|
4
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)/.exec(text);
|
|
5
|
+
if (match === null) {
|
|
6
|
+
throw new Error(`"${text}" is not a Node version`);
|
|
7
|
+
}
|
|
8
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
9
|
+
}
|
|
10
|
+
function compareVersions(left, right) {
|
|
11
|
+
for (let index = 0; index < 3; index += 1) {
|
|
12
|
+
const difference = left[index] - right[index];
|
|
13
|
+
if (difference !== 0) {
|
|
14
|
+
return difference;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Whether `range` admits `version`. Reads `^x.y.z` (the same major, from the
|
|
21
|
+
* floor; majors โฅ 1) and `>=x.y.z`, joined by `||`; anything else throws rather
|
|
22
|
+
* than admit or refuse by guess.
|
|
23
|
+
*/
|
|
24
|
+
function admits(range, version) {
|
|
25
|
+
return range.split("||").some((part) => {
|
|
26
|
+
const comparator = /^\s*(\^|>=)(\d+\.\d+\.\d+)\s*$/.exec(part);
|
|
27
|
+
if (comparator === null) {
|
|
28
|
+
throw new Error(`engines.node "${range}": the bin's Node guard reads only "^x.y.z" and ">=x.y.z" joined by "||"`);
|
|
29
|
+
}
|
|
30
|
+
const floor = versionOf(comparator[2]);
|
|
31
|
+
return (compareVersions(version, floor) >= 0 &&
|
|
32
|
+
(comparator[1] === ">=" || version[0] === floor[0]));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** The sentence a bin answers on `version`, or `undefined` when `range` admits it. */
|
|
36
|
+
export function nodeVersionRefusal(bin, packageName, range, version) {
|
|
37
|
+
return admits(range, versionOf(version))
|
|
38
|
+
? undefined
|
|
39
|
+
: `${bin}: Node ${version} is not supported; ${packageName} needs Node ${range}.`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reads the manifest at `manifestUrl`; on a Node its `engines.node` does not
|
|
43
|
+
* admit, writes the sentence to stderr, sets exit code 1 and answers `true` โ
|
|
44
|
+
* the bin then loads nothing else.
|
|
45
|
+
*/
|
|
46
|
+
export function refuseUnsupportedNode(bin, manifestUrl) {
|
|
47
|
+
const manifest = JSON.parse(readFileSync(manifestUrl, "utf8"));
|
|
48
|
+
const range = manifest.engines === undefined ? undefined : manifest.engines.node;
|
|
49
|
+
if (range === undefined) {
|
|
50
|
+
throw new Error(`${manifest.name} declares no engines.node for its bin's Node guard`);
|
|
51
|
+
}
|
|
52
|
+
const refusal = nodeVersionRefusal(bin, manifest.name, range, process.version);
|
|
53
|
+
if (refusal === undefined) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
process.stderr.write(`${refusal}\n`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D11 โ which Prisma CLI the generate step runs.
|
|
3
|
+
*
|
|
4
|
+
* `prisma`'s `latest` is a Prisma 8 release candidate (plan B32), so `npm i
|
|
5
|
+
* prisma` in a Prisma 7 project now installs a CLI this adapter's readers were
|
|
6
|
+
* never written against. Prisma's own upgrade path keeps the Prisma 7 CLI side by
|
|
7
|
+
* side as **`@prisma/prisma7`**, bin `prisma7` โ the same CLI under a
|
|
8
|
+
* version-specific name. So, in this order:
|
|
9
|
+
*
|
|
10
|
+
* 1. `@prisma/prisma7` installed โ its `prisma7` bin runs, provided the `prisma`
|
|
11
|
+
* it wraps is in the declared range;
|
|
12
|
+
* 2. otherwise `prisma`, **only** when its version is in the adapter's declared
|
|
13
|
+
* range (`peerDependencies.prisma`, read by the caller);
|
|
14
|
+
* 3. otherwise a refusal naming both, with the install command.
|
|
15
|
+
*
|
|
16
|
+
* # Where it looks
|
|
17
|
+
*
|
|
18
|
+
* Each package is looked up first from this module โ the adapter's own install,
|
|
19
|
+
* where an optional peer is linked โ and then from the project the step runs in
|
|
20
|
+
* (its working directory), where a strict installer such as pnpm leaves a
|
|
21
|
+
* package the adapter does not declare. A found package is followed to its real
|
|
22
|
+
* path, so the `prisma` that `@prisma/prisma7` wraps is the one beside it and not
|
|
23
|
+
* a `prisma` 8 hoisted next to the link.
|
|
24
|
+
*/
|
|
25
|
+
export type PrismaCli = {
|
|
26
|
+
/** The package whose bin runs: `@prisma/prisma7` or `prisma`. */
|
|
27
|
+
readonly package: "@prisma/prisma7" | "prisma";
|
|
28
|
+
/** The bin's JavaScript entry, run with the current `node`. */
|
|
29
|
+
readonly entry: string;
|
|
30
|
+
/** The `prisma` version that bin is: what the artifact is stamped with. */
|
|
31
|
+
readonly version: string;
|
|
32
|
+
};
|
|
33
|
+
export type PrismaCliResolution = {
|
|
34
|
+
readonly kind: "found";
|
|
35
|
+
readonly cli: PrismaCli;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: "refused";
|
|
38
|
+
readonly reason: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The Prisma CLI to run, or why there is none. `searchFrom` holds the places to
|
|
42
|
+
* resolve from, in order โ a module URL or a path of a file in the directory to
|
|
43
|
+
* start from; `range` is the adapter's declared `prisma` range.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolvePrismaCli(input: {
|
|
46
|
+
readonly searchFrom: readonly string[];
|
|
47
|
+
readonly range: string;
|
|
48
|
+
}): PrismaCliResolution;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { satisfiesDeclaredRange } from "./declared-support.reader.js";
|
|
5
|
+
/**
|
|
6
|
+
* The first `node_modules/<name>/package.json` on the way up from each place in
|
|
7
|
+
* turn โ Node's own lookup order, walked by hand because the manifest is all
|
|
8
|
+
* that is wanted: no `exports` map can hide it, and no `NODE_PATH` can answer
|
|
9
|
+
* from outside the install (a test runner sets one, and a resolution answered
|
|
10
|
+
* through it has produced a false green in this package before).
|
|
11
|
+
*/
|
|
12
|
+
function locate(name, searchFrom) {
|
|
13
|
+
for (const base of searchFrom) {
|
|
14
|
+
let directory = path.dirname(base.startsWith("file:") ? fileURLToPath(base) : base);
|
|
15
|
+
for (;;) {
|
|
16
|
+
if (path.basename(directory) !== "node_modules") {
|
|
17
|
+
const manifest = path.join(directory, "node_modules", name, "package.json");
|
|
18
|
+
if (existsSync(manifest)) {
|
|
19
|
+
const real = realpathSync(manifest);
|
|
20
|
+
return {
|
|
21
|
+
directory: path.dirname(real),
|
|
22
|
+
manifest: JSON.parse(readFileSync(real, "utf8")),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const parent = path.dirname(directory);
|
|
27
|
+
if (parent === directory) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
directory = parent;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
function versionOf(located) {
|
|
36
|
+
return typeof located.manifest.version === "string"
|
|
37
|
+
? located.manifest.version
|
|
38
|
+
: "with no version";
|
|
39
|
+
}
|
|
40
|
+
function binEntry(located, bin) {
|
|
41
|
+
const declared = located.manifest.bin;
|
|
42
|
+
const relative = typeof declared === "string"
|
|
43
|
+
? declared
|
|
44
|
+
: typeof declared === "object" && declared !== null
|
|
45
|
+
? declared[bin]
|
|
46
|
+
: undefined;
|
|
47
|
+
return typeof relative === "string"
|
|
48
|
+
? path.join(located.directory, relative)
|
|
49
|
+
: undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The Prisma CLI to run, or why there is none. `searchFrom` holds the places to
|
|
53
|
+
* resolve from, in order โ a module URL or a path of a file in the directory to
|
|
54
|
+
* start from; `range` is the adapter's declared `prisma` range.
|
|
55
|
+
*/
|
|
56
|
+
export function resolvePrismaCli(input) {
|
|
57
|
+
const install = `\`npm i -D "@prisma/prisma7@${input.range}"\``;
|
|
58
|
+
const prisma7 = locate("@prisma/prisma7", input.searchFrom);
|
|
59
|
+
if (prisma7 !== undefined) {
|
|
60
|
+
// The version is the wrapped CLI's, looked up from beside the wrapper.
|
|
61
|
+
const wrapped = locate("prisma", [
|
|
62
|
+
path.join(prisma7.directory, "package.json"),
|
|
63
|
+
]);
|
|
64
|
+
const entry = binEntry(prisma7, "prisma7");
|
|
65
|
+
const version = wrapped === undefined ? undefined : versionOf(wrapped);
|
|
66
|
+
if (entry !== undefined &&
|
|
67
|
+
version !== undefined &&
|
|
68
|
+
satisfiesDeclaredRange(version, input.range)) {
|
|
69
|
+
return {
|
|
70
|
+
kind: "found",
|
|
71
|
+
cli: { package: "@prisma/prisma7", entry, version },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
kind: "refused",
|
|
76
|
+
reason: `the installed \`@prisma/prisma7\` ${versionOf(prisma7)} does not run a \`prisma\` in this adapter's declared range ${input.range}; install one that does: ${install}.`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const prisma = locate("prisma", input.searchFrom);
|
|
80
|
+
if (prisma === undefined) {
|
|
81
|
+
return {
|
|
82
|
+
kind: "refused",
|
|
83
|
+
reason: `neither \`@prisma/prisma7\` nor \`prisma\` is installed where this adapter can resolve it; install the Prisma 7 CLI in this adapter's declared range ${input.range}: \`npm i -D "prisma@${input.range}"\`, or beside a Prisma 8 install ${install}.`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const version = versionOf(prisma);
|
|
87
|
+
const entry = binEntry(prisma, "prisma");
|
|
88
|
+
if (!satisfiesDeclaredRange(version, input.range) || entry === undefined) {
|
|
89
|
+
return {
|
|
90
|
+
kind: "refused",
|
|
91
|
+
reason: `the installed \`prisma\` ${version} is outside this adapter's declared range ${input.range}, and \`@prisma/prisma7\` โ the Prisma 7 CLI under its own name, bin \`prisma7\` โ is not installed beside it; install it: ${install}.`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return { kind: "found", cli: { package: "prisma", entry, version } };
|
|
95
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { PrismaCapabilitySurface } from "../discovery/capability-surface.interface.js";
|
|
2
|
+
import type { PrismaAdapterModel, PrismaReferentialActionTable, PrismaTranslationTable } from "../discovery/discovery-artifact.interface.js";
|
|
3
|
+
import type { PrismaSchemaFacts } from "../discovery/schema-facts.interface.js";
|
|
4
|
+
import type { PrismaProvider } from "../provider/provider-profile.js";
|
|
5
|
+
import type { PrismaEntityAbsence } from "./existence.gate.js";
|
|
6
|
+
import { type PrismaCli } from "./prisma-cli.resolver.js";
|
|
7
|
+
import type { PrismaReaderExemption } from "./reader-crosscheck.js";
|
|
8
|
+
/**
|
|
9
|
+
* Task 3 โ the adapter's **generate step**: a devDependency-only executable and
|
|
10
|
+
* the only module that runs `prisma` or spawns a process. Nothing under
|
|
11
|
+
* `execution/`, and nothing in `discovery/artifact.loader.ts`, imports it; the
|
|
12
|
+
* package's build `exclude` keeps `src/generate/**` out of `dist` entirely, so
|
|
13
|
+
* a deployed application never carries `typescript`, a PSL reader or a child
|
|
14
|
+
* process.
|
|
15
|
+
*
|
|
16
|
+
* **The order is fixed, and each step earns its place:**
|
|
17
|
+
*
|
|
18
|
+
* 1. **The pinned `prisma` major** (C-846). PSL's grammar and the generated
|
|
19
|
+
* client's shape are version-bound; a major this reader has never seen must
|
|
20
|
+
* stop the build rather than produce a wrong `AdapterModel` from a grammar
|
|
21
|
+
* nobody read.
|
|
22
|
+
* 2. **`@prisma/client/runtime/client` resolves** (ยง1.2 item 16). This one is
|
|
23
|
+
* first among equals, because its failure is *silent*: every generated file
|
|
24
|
+
* opens `// @ts-nocheck`, so with the runtime unresolvable a TypeScript
|
|
25
|
+
* program over the generated tree reports **zero** diagnostics while
|
|
26
|
+
* `FieldRef` degrades to its uninstantiated form and `JsonValue` stops being
|
|
27
|
+
* a union โ flipping a types-derived nullability from `true` to `false` with
|
|
28
|
+
* nothing anywhere to say so **[RUN8]**. The guard is therefore a module
|
|
29
|
+
* *resolution*, never a diagnostic count: a diagnostic count is exactly the
|
|
30
|
+
* instrument that reads clean in this failure.
|
|
31
|
+
* 3. **`prisma generate`**, run by this step itself. The two sources must
|
|
32
|
+
* describe one instant; a client generated by some earlier command may
|
|
33
|
+
* describe an older schema, and nothing downstream could tell.
|
|
34
|
+
* 4. **Both sources read in that same run** โ PSL for the semantic model, the
|
|
35
|
+
* ๐ข generated types for the capability surface and for existence.
|
|
36
|
+
* 5. **The structural checks, in that order.** The existence gate first (T-3.1
|
|
37
|
+
* invariant 3), because it decides *which* entities exist and a cross-check
|
|
38
|
+
* of an entity nobody admitted is noise; then the reader-versus-reader
|
|
39
|
+
* cross-check (`reader-crosscheck.ts`), which answers the reverse direction
|
|
40
|
+
* the gate hands it and every other fact both sources carry. Its findings
|
|
41
|
+
* stop the step; its two documented exemptions are reported and carried out
|
|
42
|
+
* on the result.
|
|
43
|
+
* 6. **Emit** one TypeScript module (ADR 0009).
|
|
44
|
+
*
|
|
45
|
+
* The plan's ยง9 sketch puts the runtime check *after* `prisma generate`; the
|
|
46
|
+
* order above is the brief's, and it is the better one โ module resolution
|
|
47
|
+
* walks `node_modules` upward from the client directory and does not need the
|
|
48
|
+
* directory populated, so nothing is gained by generating output first that the
|
|
49
|
+
* step is about to refuse to read.
|
|
50
|
+
*
|
|
51
|
+
* **The two readers fail differently, and the step keeps them different.** A
|
|
52
|
+
* PSL `unhandled` entry means *I located a token I do not model*: there is a
|
|
53
|
+
* construct, a spelling and a site to report, so they are aggregated and
|
|
54
|
+
* reported together. A types-reader failure means *I cannot read the surface at
|
|
55
|
+
* all*: there is nothing to record, so it throws. Inventing an `unhandled`
|
|
56
|
+
* vocabulary for the type surface would be a second parallel representation of
|
|
57
|
+
* "something went wrong" for no gain.
|
|
58
|
+
*/
|
|
59
|
+
/** The `prisma` major this reader's grammar was written against (C-846). */
|
|
60
|
+
export declare const PINNED_PRISMA_MAJOR = 7;
|
|
61
|
+
export declare class PrismaGenerateStepError extends Error {
|
|
62
|
+
readonly name = "PrismaGenerateStepError";
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* What composition produces: the three halves the artifact carries.
|
|
66
|
+
*
|
|
67
|
+
* They are composed together and emitted apart. The `model` is core's โ hashed
|
|
68
|
+
* and Contract-bound โ while `translation` is the adapter's Prisma addressing and
|
|
69
|
+
* `referentialActions` is what the schema's resolved `@relation(onDelete:)` and
|
|
70
|
+
* `@relation(onUpdate:)` arguments say. Neither of the latter two is part of the
|
|
71
|
+
* model, so both stay out of the hash: a `@@unique(name:)` rename must not move
|
|
72
|
+
* the Contract identity, and core has no referential-action vocabulary for a
|
|
73
|
+
* Contract to carry. All three come from one pass over one field list, so they
|
|
74
|
+
* cannot disagree about which identifiers or which edges exist.
|
|
75
|
+
*/
|
|
76
|
+
export type PrismaComposedArtifact = {
|
|
77
|
+
readonly model: PrismaAdapterModel;
|
|
78
|
+
readonly translation: PrismaTranslationTable;
|
|
79
|
+
readonly referentialActions: PrismaReferentialActionTable;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Composition of the two readers' facts into the artifact's two halves.
|
|
83
|
+
*
|
|
84
|
+
* It is a parameter rather than a call, because composition is
|
|
85
|
+
* `discovery/model.discoverer.ts`'s (Task 6) and this step's job is order and
|
|
86
|
+
* refusal over external effects. The step hands over only what it has verified:
|
|
87
|
+
* both readers' output, and the resource names the existence gate admitted.
|
|
88
|
+
*/
|
|
89
|
+
export type PrismaModelComposer = (input: {
|
|
90
|
+
readonly facts: PrismaSchemaFacts;
|
|
91
|
+
readonly surface: PrismaCapabilitySurface;
|
|
92
|
+
readonly admitted: readonly string[];
|
|
93
|
+
}) => PrismaComposedArtifact;
|
|
94
|
+
/**
|
|
95
|
+
* The step's external world, in one record.
|
|
96
|
+
*
|
|
97
|
+
* Every member is an effect this package does not own โ a child process, a
|
|
98
|
+
* version on disk, a module resolution, a file write โ which is why they are
|
|
99
|
+
* injectable: the step's contract is the *order* it performs them in and the
|
|
100
|
+
* points at which it refuses, and neither is observable when the effects are
|
|
101
|
+
* unobservable. {@link createPrismaGenerateToolchain} is the real one.
|
|
102
|
+
*/
|
|
103
|
+
export type PrismaGenerateToolchain = {
|
|
104
|
+
readonly installedPrismaVersion: () => Promise<string>;
|
|
105
|
+
readonly clientRuntimeResolves: (clientDirectory: string) => boolean;
|
|
106
|
+
readonly runPrismaGenerate: (schema: string) => Promise<void>;
|
|
107
|
+
readonly readSchema: (location: string) => Promise<PrismaSchemaFacts>;
|
|
108
|
+
readonly readSurface: (clientDirectory: string) => PrismaCapabilitySurface;
|
|
109
|
+
readonly writeArtifact: (file: string, source: string) => Promise<void>;
|
|
110
|
+
};
|
|
111
|
+
export type PrismaGenerateRequest = {
|
|
112
|
+
/** The `schema.prisma` file, or a Prisma 7 schema folder. */
|
|
113
|
+
readonly schema: string;
|
|
114
|
+
/** The generator's `output` directory: the ๐ข files' root. */
|
|
115
|
+
readonly clientDirectory: string;
|
|
116
|
+
readonly provider: PrismaProvider;
|
|
117
|
+
/** Where the emitted TypeScript artifact module is written. */
|
|
118
|
+
readonly artifactFile: string;
|
|
119
|
+
readonly composeModel: PrismaModelComposer;
|
|
120
|
+
readonly toolchain?: PrismaGenerateToolchain;
|
|
121
|
+
};
|
|
122
|
+
export type PrismaGenerateResult = {
|
|
123
|
+
readonly artifactFile: string;
|
|
124
|
+
/** The emitted module's exact bytes. */
|
|
125
|
+
readonly source: string;
|
|
126
|
+
readonly modelHash: string;
|
|
127
|
+
/** Resource names the ๐ข types admitted, in PSL declaration order. */
|
|
128
|
+
readonly admitted: readonly string[];
|
|
129
|
+
/** PSL-only entities the schema itself explained away. */
|
|
130
|
+
readonly excluded: readonly PrismaEntityAbsence[];
|
|
131
|
+
/**
|
|
132
|
+
* Reader disagreements that are understood โ the `Json` nullability one and
|
|
133
|
+
* C-815's unexplained `AtLeast` key. Carried out rather than swallowed, so a
|
|
134
|
+
* caller can print them and a spec can assert them by name and reason.
|
|
135
|
+
*/
|
|
136
|
+
readonly exemptions: readonly PrismaReaderExemption[];
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* The Prisma CLI this step runs, chosen as D11 states (`prisma-cli.resolver.ts`):
|
|
140
|
+
* `@prisma/prisma7`'s `prisma7` when it is installed, else `prisma` when its
|
|
141
|
+
* version is in the adapter's declared range, else a refusal naming both. Looked
|
|
142
|
+
* up from this package โ where an optional peer is linked โ and then from the
|
|
143
|
+
* project the step runs in.
|
|
144
|
+
*/
|
|
145
|
+
export declare function resolveInstalledPrismaCli(): PrismaCli;
|
|
146
|
+
/**
|
|
147
|
+
* The version fence's input: the version of the Prisma CLI this step runs, which
|
|
148
|
+
* is the tool that produces the client and the grammar the PSL reader was
|
|
149
|
+
* written against. (`@prisma/client`'s version is a different fact, fenced at
|
|
150
|
+
* load time against the artifact โ see `discovery/artifact.loader.ts`.)
|
|
151
|
+
*/
|
|
152
|
+
export declare function readInstalledPrismaVersion(): Promise<string>;
|
|
153
|
+
/**
|
|
154
|
+
* Whether `@prisma/client/runtime/client` resolves from inside the generated
|
|
155
|
+
* tree โ the single question ยง1.2 item 16 turns on.
|
|
156
|
+
*
|
|
157
|
+
* Asked as a module resolution, never as a diagnostic count, and asked from a
|
|
158
|
+
* file path *inside* `clientDirectory` because resolution walks `node_modules`
|
|
159
|
+
* upward from the importer. The directory need not exist yet: resolution is a
|
|
160
|
+
* path question, which is what lets this fence run before `prisma generate`.
|
|
161
|
+
*/
|
|
162
|
+
export declare function clientRuntimeResolves(clientDirectory: string): boolean;
|
|
163
|
+
export declare function createPrismaGenerateToolchain(): PrismaGenerateToolchain;
|
|
164
|
+
export declare function runPrismaGenerateStep(request: PrismaGenerateRequest): Promise<PrismaGenerateResult>;
|