@prisma/composer-prisma-cloud 0.18.0-dev.1 → 0.18.0-dev.2
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/auth/auth-service.mjs +4 -2
- package/dist/auth/auth-service.mjs.map +1 -1
- package/dist/auth/{constants-B7YSuQsF-CbQEXXm0.mjs → constants-D1wCvoU3-gX4AfOjK.mjs} +4 -2
- package/dist/auth/constants-D1wCvoU3-gX4AfOjK.mjs.map +1 -0
- package/dist/auth/index.mjs +2 -2
- package/dist/auth/index.mjs.map +1 -1
- package/dist/auth/pack.mjs +2 -2
- package/dist/auth/pack.mjs.map +1 -1
- package/dist/auth/testing.mjs +2317 -1146
- package/dist/auth/testing.mjs.map +1 -1
- package/package.json +21 -21
- package/dist/auth/constants-B7YSuQsF-CbQEXXm0.mjs.map +0 -1
package/dist/auth/testing.mjs
CHANGED
|
@@ -18391,7 +18391,7 @@ const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
|
|
|
18391
18391
|
inst.keyType = def.keyType;
|
|
18392
18392
|
inst.valueType = def.valueType;
|
|
18393
18393
|
});
|
|
18394
|
-
function record(keyType, valueType, params) {
|
|
18394
|
+
function record$1(keyType, valueType, params) {
|
|
18395
18395
|
if (!valueType || !valueType._zod) return new ZodRecord({
|
|
18396
18396
|
type: "record",
|
|
18397
18397
|
keyType: string$1(),
|
|
@@ -28188,7 +28188,7 @@ const linkSocialAccount = createAuthEndpoint("/link-social", {
|
|
|
28188
28188
|
/**
|
|
28189
28189
|
* Any additional data to pass through the oauth flow.
|
|
28190
28190
|
*/
|
|
28191
|
-
additionalData: record(string$1(), any()).optional()
|
|
28191
|
+
additionalData: record$1(string$1(), any()).optional()
|
|
28192
28192
|
}),
|
|
28193
28193
|
use: [sessionMiddleware],
|
|
28194
28194
|
metadata: { openapi: {
|
|
@@ -29514,7 +29514,7 @@ const socialSignInBodySchema = object({
|
|
|
29514
29514
|
/**
|
|
29515
29515
|
* Additional data to be passed through the OAuth flow
|
|
29516
29516
|
*/
|
|
29517
|
-
additionalData: record(string$1(), any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" })
|
|
29517
|
+
additionalData: record$1(string$1(), any()).optional().meta({ description: "Additional data to be passed through the OAuth flow" })
|
|
29518
29518
|
});
|
|
29519
29519
|
const signInSocial = () => createAuthEndpoint("/sign-in/social", {
|
|
29520
29520
|
method: "POST",
|
|
@@ -29788,7 +29788,7 @@ const signUpEmailBodySchema = object({
|
|
|
29788
29788
|
image: string$1().optional(),
|
|
29789
29789
|
callbackURL: string$1().optional(),
|
|
29790
29790
|
rememberMe: boolean$1().optional()
|
|
29791
|
-
}).and(record(string$1(), any()));
|
|
29791
|
+
}).and(record$1(string$1(), any()));
|
|
29792
29792
|
const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
|
|
29793
29793
|
method: "POST",
|
|
29794
29794
|
operationId: "signUpWithEmailAndPassword",
|
|
@@ -30036,7 +30036,7 @@ const signUpEmail = () => createAuthEndpoint("/sign-up/email", {
|
|
|
30036
30036
|
});
|
|
30037
30037
|
});
|
|
30038
30038
|
init_error();
|
|
30039
|
-
const updateSessionBodySchema = record(string$1().meta({ description: "Field name must be a string" }), any());
|
|
30039
|
+
const updateSessionBodySchema = record$1(string$1().meta({ description: "Field name must be a string" }), any());
|
|
30040
30040
|
const updateSession = () => createAuthEndpoint("/update-session", {
|
|
30041
30041
|
method: "POST",
|
|
30042
30042
|
operationId: "updateSession",
|
|
@@ -30085,7 +30085,7 @@ const updateSession = () => createAuthEndpoint("/update-session", {
|
|
|
30085
30085
|
return ctx.json({ session: parseSessionOutput(ctx.context.options, newSession) });
|
|
30086
30086
|
});
|
|
30087
30087
|
init_error();
|
|
30088
|
-
const updateUserBodySchema = record(string$1().meta({ description: "Field name must be a string" }), any());
|
|
30088
|
+
const updateUserBodySchema = record$1(string$1().meta({ description: "Field name must be a string" }), any());
|
|
30089
30089
|
const updateUser = () => createAuthEndpoint("/update-user", {
|
|
30090
30090
|
method: "POST",
|
|
30091
30091
|
operationId: "updateUser",
|
|
@@ -52211,7 +52211,7 @@ const createUserBodySchema = object({
|
|
|
52211
52211
|
/**
|
|
52212
52212
|
* extra fields for user
|
|
52213
52213
|
*/
|
|
52214
|
-
data: record(string$1(), any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." })
|
|
52214
|
+
data: record$1(string$1(), any()).optional().meta({ description: "Extra fields for the user. Including custom additional fields." })
|
|
52215
52215
|
});
|
|
52216
52216
|
/**
|
|
52217
52217
|
* ### Endpoint
|
|
@@ -52309,7 +52309,7 @@ const createUser = (opts) => createAuthEndpoint("/admin/create-user", {
|
|
|
52309
52309
|
});
|
|
52310
52310
|
const adminUpdateUserBodySchema = object({
|
|
52311
52311
|
userId: string().meta({ description: "The user id" }),
|
|
52312
|
-
data: record(any(), any()).meta({ description: "The user data to update" })
|
|
52312
|
+
data: record$1(any(), any()).meta({ description: "The user data to update" })
|
|
52313
52313
|
});
|
|
52314
52314
|
/**
|
|
52315
52315
|
* ### Endpoint
|
|
@@ -52945,7 +52945,7 @@ const setUserPassword = (opts) => createAuthEndpoint("/admin/set-user-password",
|
|
|
52945
52945
|
const userHasPermissionBodySchema = object({
|
|
52946
52946
|
userId: string().optional().meta({ description: `The user id. Eg: "user-id"` }),
|
|
52947
52947
|
role: string$1().optional().meta({ description: `The role to check permission for. Eg: "admin"` })
|
|
52948
|
-
}).and(xor([object({ permission: record(string$1(), array$1(string$1())) }), object({ permissions: record(string$1(), array$1(string$1())) })]));
|
|
52948
|
+
}).and(xor([object({ permission: record$1(string$1(), array$1(string$1())) }), object({ permissions: record$1(string$1(), array$1(string$1())) })]));
|
|
52949
52949
|
/**
|
|
52950
52950
|
* ### Endpoint
|
|
52951
52951
|
*
|
|
@@ -53397,8 +53397,8 @@ const schema = { jwks: { fields: {
|
|
|
53397
53397
|
} } };
|
|
53398
53398
|
init_error();
|
|
53399
53399
|
const signJWTBodySchema = object({
|
|
53400
|
-
payload: record(string$1(), any()),
|
|
53401
|
-
overrideOptions: record(string$1(), any()).optional()
|
|
53400
|
+
payload: record$1(string$1(), any()),
|
|
53401
|
+
overrideOptions: record$1(string$1(), any()).optional()
|
|
53402
53402
|
});
|
|
53403
53403
|
const verifyJWTBodySchema = object({
|
|
53404
53404
|
token: string$1(),
|
|
@@ -53592,7 +53592,7 @@ const signInMagicLinkBodySchema = object({
|
|
|
53592
53592
|
callbackURL: string$1().meta({ description: "URL to redirect after magic link verification" }).optional(),
|
|
53593
53593
|
newUserCallbackURL: string$1().meta({ description: "URL to redirect after new user signup. Only used if the user is registering for the first time." }).optional(),
|
|
53594
53594
|
errorCallbackURL: string$1().meta({ description: "URL to redirect after error." }).optional(),
|
|
53595
|
-
metadata: record(string$1(), any()).meta({ description: "Additional metadata to pass to sendMagicLink." }).optional()
|
|
53595
|
+
metadata: record$1(string$1(), any()).meta({ description: "Additional metadata to pass to sendMagicLink." }).optional()
|
|
53596
53596
|
});
|
|
53597
53597
|
const magicLinkVerifyQuerySchema = object({
|
|
53598
53598
|
token: string$1().meta({ description: "Verification token" }),
|
|
@@ -58072,6 +58072,7 @@ var contract_default = {
|
|
|
58072
58072
|
},
|
|
58073
58073
|
"relations": { "user": {
|
|
58074
58074
|
"cardinality": "N:1",
|
|
58075
|
+
"nullable": false,
|
|
58075
58076
|
"on": {
|
|
58076
58077
|
"localFields": ["userId"],
|
|
58077
58078
|
"targetFields": ["id"]
|
|
@@ -58220,6 +58221,7 @@ var contract_default = {
|
|
|
58220
58221
|
},
|
|
58221
58222
|
"relations": { "user": {
|
|
58222
58223
|
"cardinality": "N:1",
|
|
58224
|
+
"nullable": false,
|
|
58223
58225
|
"on": {
|
|
58224
58226
|
"localFields": ["userId"],
|
|
58225
58227
|
"targetFields": ["id"]
|
|
@@ -60018,7 +60020,7 @@ function postgresResolveDefault(def, resolvedNativeType) {
|
|
|
60018
60020
|
return parsePostgresDefault(def.expression, resolvedNativeType) ?? def;
|
|
60019
60021
|
}
|
|
60020
60022
|
/**
|
|
60021
|
-
* A bug in Prisma
|
|
60023
|
+
* A bug in Prisma 8, not a user error. Never catch this except at the
|
|
60022
60024
|
* outermost boundary for crash reporting — an InternalError means an invariant
|
|
60023
60025
|
* broke and the process cannot reliably continue. User-facing failures use
|
|
60024
60026
|
* `structuredError` with a dotted code instead.
|
|
@@ -61399,7 +61401,7 @@ function isCodecTrait(value) {
|
|
|
61399
61401
|
*/
|
|
61400
61402
|
const voidParamsSchema = { "~standard": {
|
|
61401
61403
|
version: 1,
|
|
61402
|
-
vendor: "prisma
|
|
61404
|
+
vendor: "prisma",
|
|
61403
61405
|
validate: (input) => input === void 0 ? { value: void 0 } : { issues: [{ message: "unexpected typeParams for non-parameterized codec (void params expected)" }] }
|
|
61404
61406
|
} };
|
|
61405
61407
|
function runtimeError(code, message, details) {
|
|
@@ -61469,16 +61471,13 @@ function validateCodecTypeParams(descriptor, ref) {
|
|
|
61469
61471
|
}
|
|
61470
61472
|
/**
|
|
61471
61473
|
* Resolves a `Codec` instance: validates `ref.typeParams` via
|
|
61472
|
-
* {@link validateCodecTypeParams} then calls `descriptor.factory(validated)(ctx)
|
|
61473
|
-
*
|
|
61474
|
-
*
|
|
61475
|
-
* `P` to `any`, so the factory is narrowed to `(params: unknown) => (ctx) => Codec`
|
|
61476
|
-
* at the call boundary. The `paramsSchema` validates the input above before we
|
|
61477
|
-
* forward it, so the narrowing is safe by construction.
|
|
61474
|
+
* {@link validateCodecTypeParams} then calls `descriptor.factory(validated)(ctx)`
|
|
61475
|
+
* as a method on `descriptor`, preserving `this` for factories that build
|
|
61476
|
+
* their returned codec from the descriptor instance (e.g. `new XCodec(this)`).
|
|
61478
61477
|
*/
|
|
61479
61478
|
function materializeCodec(descriptor, ref, ctx) {
|
|
61480
61479
|
const validated = validateCodecTypeParams(descriptor, ref);
|
|
61481
|
-
return
|
|
61480
|
+
return descriptor.factory(validated)(ctx);
|
|
61482
61481
|
}
|
|
61483
61482
|
/**
|
|
61484
61483
|
* Renders a string as a TypeScript source-text literal.
|
|
@@ -62783,6 +62782,103 @@ function indexInputFromSerialized(flat) {
|
|
|
62783
62782
|
};
|
|
62784
62783
|
}
|
|
62785
62784
|
/**
|
|
62785
|
+
* Stable code emitted by the runtime when an in-flight `execute()`
|
|
62786
|
+
* is cancelled via the per-query `AbortSignal`. The envelope's
|
|
62787
|
+
* `details.phase` distinguishes where the abort was observed:
|
|
62788
|
+
*
|
|
62789
|
+
* - `'encode'` — abort fired during `encodeParams` (SQL) or
|
|
62790
|
+
* `resolveValue` (Mongo).
|
|
62791
|
+
* - `'decode'` — abort fired during `decodeRow` / `decodeField`.
|
|
62792
|
+
* - `'stream'` — abort fired between rows or before any codec call
|
|
62793
|
+
* (already-aborted at entry).
|
|
62794
|
+
* - `'beforeQuery'` / `'beforeExecute'` / `'afterQuery'` /
|
|
62795
|
+
* `'afterExecute'` / `'onRow'` — abort fired on entry to or during
|
|
62796
|
+
* the corresponding middleware phase
|
|
62797
|
+
* (cooperative cancellation per the param-transform seam).
|
|
62798
|
+
*/
|
|
62799
|
+
const RUNTIME_ABORTED = "RUNTIME.ABORTED";
|
|
62800
|
+
/**
|
|
62801
|
+
* Construct a `RUNTIME.ABORTED` envelope. Phase distinguishes where the
|
|
62802
|
+
* abort was observed — codec call sites (`encode` / `decode` / `stream`)
|
|
62803
|
+
* or operation-specific middleware seams, as
|
|
62804
|
+
* enumerated on {@link RuntimeAbortedPhase}. Cause carries
|
|
62805
|
+
* `signal.reason` verbatim from the platform — native abort produces a
|
|
62806
|
+
* `DOMException`, explicit `controller.abort(reason)` produces whatever
|
|
62807
|
+
* the caller passed. No synthesis happens here.
|
|
62808
|
+
*/
|
|
62809
|
+
function runtimeAborted(phase, cause) {
|
|
62810
|
+
const envelope = runtimeError(RUNTIME_ABORTED, `Operation aborted during ${phase}`, { phase });
|
|
62811
|
+
return Object.assign(envelope, { cause });
|
|
62812
|
+
}
|
|
62813
|
+
/**
|
|
62814
|
+
* Throw a phase-tagged `RUNTIME.ABORTED` envelope if the supplied
|
|
62815
|
+
* context is already aborted at the precheck site. Centralises the
|
|
62816
|
+
* `if (ctx.signal?.aborted) throw runtimeAborted(...)` pattern that
|
|
62817
|
+
* every codec dispatch site (and the `beforeExecute` middleware phase)
|
|
62818
|
+
* repeats. Accepts both the framework `CodecCallContext` and the
|
|
62819
|
+
* `RuntimeMiddlewareContext`; both expose `signal?: AbortSignal`.
|
|
62820
|
+
*/
|
|
62821
|
+
function checkAborted(ctx, phase) {
|
|
62822
|
+
if (ctx.signal?.aborted) throw runtimeAborted(phase, ctx.signal.reason);
|
|
62823
|
+
}
|
|
62824
|
+
/**
|
|
62825
|
+
* Race a per-cell `Promise.all` (or any other in-flight work promise) against
|
|
62826
|
+
* the supplied abort signal so the runtime returns `RUNTIME.ABORTED` promptly
|
|
62827
|
+
* even when codec bodies ignore the signal. In-flight bodies that ignore the
|
|
62828
|
+
* signal are abandoned and run to completion in the background — the
|
|
62829
|
+
* cooperative-cancellation contract documented in ADR 204.
|
|
62830
|
+
*
|
|
62831
|
+
* Call sites still SHOULD pre-check `signal.aborted` and short-circuit with
|
|
62832
|
+
* a phase-tagged `RUNTIME.ABORTED` envelope before invoking this helper —
|
|
62833
|
+
* that path is the canonical "aborted at entry" surface and avoids
|
|
62834
|
+
* scheduling the work promise. As a defensive belt-and-braces, this helper
|
|
62835
|
+
* also handles the already-aborted case internally: `AbortSignal` does not
|
|
62836
|
+
* replay past abort events to listeners registered after the abort, so we
|
|
62837
|
+
* inspect `signal.aborted` synchronously and reject with the sentinel
|
|
62838
|
+
* before installing the listener. The rejection is still attributed to the
|
|
62839
|
+
* abort path via the sentinel-identity check.
|
|
62840
|
+
*
|
|
62841
|
+
* Distinguishing the rejection source is load-bearing for AC-ERR4
|
|
62842
|
+
* (`RUNTIME.ENCODE_FAILED` / `RUNTIME.DECODE_FAILED` pass through unchanged).
|
|
62843
|
+
* The semantically equivalent `abortable(signal)` helper in
|
|
62844
|
+
* `@internal/utils` rejects with `signal.reason ?? new DOMException(...)`,
|
|
62845
|
+
* which is not stably distinguishable from a codec-thrown error by identity
|
|
62846
|
+
* alone (a fresh fallback DOMException is allocated per call). We instead
|
|
62847
|
+
* track abort attribution with a unique sentinel: only the `onAbort` listener
|
|
62848
|
+
* installed here ever rejects with the sentinel, so an `error === sentinel`
|
|
62849
|
+
* identity check after the race is unambiguous.
|
|
62850
|
+
*
|
|
62851
|
+
* Lives in `framework-components` (rather than the SQL family, where it
|
|
62852
|
+
* originated in m2) so every family runtime that needs cooperative
|
|
62853
|
+
* cancellation around a codec-dispatch `Promise.all` (SQL encode + decode
|
|
62854
|
+
* today, Mongo encode in m3) shares the same attribution logic.
|
|
62855
|
+
*/
|
|
62856
|
+
async function raceAgainstAbort(work, signal, phase) {
|
|
62857
|
+
if (signal === void 0) return await work;
|
|
62858
|
+
const sentinel = { reason: void 0 };
|
|
62859
|
+
let onAbort;
|
|
62860
|
+
const abortPromise = new Promise((_, reject) => {
|
|
62861
|
+
if (signal.aborted) {
|
|
62862
|
+
sentinel.reason = signal.reason;
|
|
62863
|
+
reject(sentinel);
|
|
62864
|
+
return;
|
|
62865
|
+
}
|
|
62866
|
+
onAbort = () => {
|
|
62867
|
+
sentinel.reason = signal.reason;
|
|
62868
|
+
reject(sentinel);
|
|
62869
|
+
};
|
|
62870
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
62871
|
+
});
|
|
62872
|
+
try {
|
|
62873
|
+
return await Promise.race([work, abortPromise]);
|
|
62874
|
+
} catch (error) {
|
|
62875
|
+
if (error === sentinel) throw runtimeAborted(phase, sentinel.reason);
|
|
62876
|
+
throw error;
|
|
62877
|
+
} finally {
|
|
62878
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
62879
|
+
}
|
|
62880
|
+
}
|
|
62881
|
+
/**
|
|
62786
62882
|
* Sentinel kind for the legacy codec-triple shape persisted under
|
|
62787
62883
|
* `SqlStorage.types`. Plain JSON-clean object literals carry this
|
|
62788
62884
|
* discriminator so the polymorphic slot dispatch can route them down
|
|
@@ -63942,7 +64038,7 @@ function classifyEnumMemberType(block) {
|
|
|
63942
64038
|
*/
|
|
63943
64039
|
function resolveEnumCodecId(block, ctx) {
|
|
63944
64040
|
const sourceId = ctx.sourceId ?? "unknown";
|
|
63945
|
-
const typeAttr = block.
|
|
64041
|
+
const typeAttr = block.attributes["type"];
|
|
63946
64042
|
if (typeAttr === void 0) {
|
|
63947
64043
|
const inferredKind = classifyEnumMemberType(block);
|
|
63948
64044
|
if (inferredKind === null || ctx.enumInferenceCodecs === void 0) {
|
|
@@ -63959,20 +64055,11 @@ function resolveEnumCodecId(block, ctx) {
|
|
|
63959
64055
|
codecSpan: block.span
|
|
63960
64056
|
};
|
|
63961
64057
|
}
|
|
63962
|
-
const
|
|
63963
|
-
|
|
63964
|
-
if (codecId === void 0) {
|
|
63965
|
-
ctx.diagnostics?.push({
|
|
63966
|
-
code: "PSL_ENUM_MISSING_TYPE",
|
|
63967
|
-
message: `enum "${block.name}" @@type attribute must have a quoted codec id argument`,
|
|
63968
|
-
sourceId,
|
|
63969
|
-
span: typeAttr.span
|
|
63970
|
-
});
|
|
63971
|
-
return;
|
|
63972
|
-
}
|
|
64058
|
+
const codecId = typeAttr.args["codecId"];
|
|
64059
|
+
invariant(typeof codecId === "string", "@@type on an enum block parses one string argument");
|
|
63973
64060
|
return {
|
|
63974
64061
|
codecId,
|
|
63975
|
-
codecSpan: typeAttr.
|
|
64062
|
+
codecSpan: typeAttr.span
|
|
63976
64063
|
};
|
|
63977
64064
|
}
|
|
63978
64065
|
function isAuthoringArgRef(value) {
|
|
@@ -64064,7 +64151,11 @@ function isWellFormedDescriptor(value, descriptorKind) {
|
|
|
64064
64151
|
if (!("required" in name) || typeof name.required !== "boolean") return false;
|
|
64065
64152
|
if (!("parameters" in value)) return false;
|
|
64066
64153
|
const parameters = value.parameters;
|
|
64067
|
-
|
|
64154
|
+
if (typeof parameters !== "object" || parameters === null || Array.isArray(parameters)) return false;
|
|
64155
|
+
if (!("attributes" in value) || value.attributes === void 0) return true;
|
|
64156
|
+
const attributes = value.attributes;
|
|
64157
|
+
if (typeof attributes !== "object" || attributes === null || Array.isArray(attributes)) return false;
|
|
64158
|
+
return Object.values(attributes).every((factory) => typeof factory === "function");
|
|
64068
64159
|
}
|
|
64069
64160
|
case "modelAttribute":
|
|
64070
64161
|
if (!("attribute" in value) || typeof value.attribute !== "string" || value.attribute.length === 0) return false;
|
|
@@ -64118,6 +64209,25 @@ function mergeAuthoringNamespaces(target, source, path, descriptorKind, label) {
|
|
|
64118
64209
|
mergeAuthoringNamespaces(existingValue, sourceValue, currentPath, descriptorKind, label);
|
|
64119
64210
|
}
|
|
64120
64211
|
}
|
|
64212
|
+
const ATTRIBUTE_SPEC_LEVELS = ["model", "field"];
|
|
64213
|
+
function mergeAuthoringAttributeSpecs(target, source, contributedBy, owners) {
|
|
64214
|
+
const invalidContribution = (detail) => runtimeError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Invalid authoring attributeSpecs contribution from descriptor "${contributedBy}". ${detail}`);
|
|
64215
|
+
if (!isCopyableNamespaceObject(source)) throw invalidContribution("Expected a record carrying a \"model\" and a \"field\" level.");
|
|
64216
|
+
for (const level of ATTRIBUTE_SPEC_LEVELS) {
|
|
64217
|
+
const contributed = source[level];
|
|
64218
|
+
if (!isCopyableNamespaceObject(contributed)) throw invalidContribution(`The "${level}" level must be a record of spec factories keyed by attribute name.`);
|
|
64219
|
+
for (const [attribute, factory] of Object.entries(contributed)) {
|
|
64220
|
+
const entryPath = `${level}.${attribute}`;
|
|
64221
|
+
const invalidEntry = (detail) => runtimeError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Invalid authoring attributeSpecs entry "${entryPath}" contributed by descriptor "${contributedBy}". ${detail}`);
|
|
64222
|
+
if (attribute === "__proto__" || attribute === "constructor" || attribute === "prototype") throw invalidEntry(`Attribute names must not use "${attribute}".`);
|
|
64223
|
+
if (typeof factory !== "function") throw invalidEntry("Each entry must be a spec factory function.");
|
|
64224
|
+
const existingOwner = owners.get(entryPath);
|
|
64225
|
+
if (existingOwner !== void 0) throw runtimeError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Duplicate authoring attributeSpecs entry "${entryPath}". Descriptor "${contributedBy}" conflicts with "${existingOwner}". Each attribute name may be claimed once per level.`);
|
|
64226
|
+
owners.set(entryPath, contributedBy);
|
|
64227
|
+
target[level][attribute] = factory;
|
|
64228
|
+
}
|
|
64229
|
+
}
|
|
64230
|
+
}
|
|
64121
64231
|
/**
|
|
64122
64232
|
* Collects the full dotted paths of every well-formed descriptor of
|
|
64123
64233
|
* `descriptorKind` in a raw contribution tree, using the same boundary
|
|
@@ -64654,6 +64764,11 @@ function assembleAuthoringContributions(descriptors) {
|
|
|
64654
64764
|
const entityTypes = {};
|
|
64655
64765
|
const pslBlockDescriptors = {};
|
|
64656
64766
|
const modelAttributes = {};
|
|
64767
|
+
const attributeSpecs = {
|
|
64768
|
+
model: {},
|
|
64769
|
+
field: {}
|
|
64770
|
+
};
|
|
64771
|
+
const attributeSpecOwners = /* @__PURE__ */ new Map();
|
|
64657
64772
|
const pathOwners = /* @__PURE__ */ new Map();
|
|
64658
64773
|
const claimContributedPaths = (namespace, descriptorKind, label, descriptorId) => {
|
|
64659
64774
|
for (const path of collectContributedDescriptorPaths(namespace, descriptorKind)) {
|
|
@@ -64692,6 +64807,7 @@ function assembleAuthoringContributions(descriptors) {
|
|
|
64692
64807
|
mergeAuthoringNamespaces(pslBlockDescriptors, descriptor.authoring.pslBlockDescriptors, [], "pslBlock", "pslBlock");
|
|
64693
64808
|
}
|
|
64694
64809
|
if (descriptor.authoring?.modelAttributes) mergeAuthoringNamespaces(modelAttributes, descriptor.authoring.modelAttributes, [], "modelAttribute", "modelAttribute");
|
|
64810
|
+
if (descriptor.authoring?.attributeSpecs) mergeAuthoringAttributeSpecs(attributeSpecs, descriptor.authoring.attributeSpecs, descriptorId, attributeSpecOwners);
|
|
64695
64811
|
}
|
|
64696
64812
|
const fieldNamespace = field;
|
|
64697
64813
|
const typeNamespace = type;
|
|
@@ -64706,6 +64822,7 @@ function assembleAuthoringContributions(descriptors) {
|
|
|
64706
64822
|
entityTypes: entityTypeNamespace,
|
|
64707
64823
|
pslBlockDescriptors: pslBlockDescriptorNamespace,
|
|
64708
64824
|
modelAttributes: modelAttributeNamespace,
|
|
64825
|
+
attributeSpecs,
|
|
64709
64826
|
...valueObjectStorageDeclaration !== void 0 ? { valueObjectStorageType: valueObjectStorageDeclaration.name } : {}
|
|
64710
64827
|
};
|
|
64711
64828
|
}
|
|
@@ -66019,12 +66136,13 @@ var SqlCheckConstraintIR = class SqlCheckConstraintIR extends SqlSchemaIRNode {
|
|
|
66019
66136
|
* Structural equality for two resolved column defaults, ported from the
|
|
66020
66137
|
* relational walk's `columnDefaultsEqual` normalized branch: kinds must
|
|
66021
66138
|
* match; literal values are normalized (Date and temporal-typed strings to
|
|
66022
|
-
* ISO instants
|
|
66023
|
-
*
|
|
66139
|
+
* ISO instants, and a 64-bit-integer native type's safe-integer number to
|
|
66140
|
+
* its decimal-text spelling) then compared canonically (JSON objects match
|
|
66141
|
+
* their canonical string form); function expressions compare case- and
|
|
66024
66142
|
* whitespace-insensitively.
|
|
66025
66143
|
*
|
|
66026
|
-
* `nativeType` provides the temporal-normalization context (the
|
|
66027
|
-
* side's resolved native type in a diff comparison).
|
|
66144
|
+
* `nativeType` provides the temporal- and int64-normalization context (the
|
|
66145
|
+
* actual side's resolved native type in a diff comparison).
|
|
66028
66146
|
*/
|
|
66029
66147
|
function resolvedDefaultsEqual(expected, actual, nativeType) {
|
|
66030
66148
|
if (expected.kind !== actual.kind) return false;
|
|
@@ -66040,12 +66158,18 @@ function isTemporalNativeType(nativeType) {
|
|
|
66040
66158
|
const normalized = nativeType.toLowerCase();
|
|
66041
66159
|
return normalized.includes("timestamp") || normalized === "date";
|
|
66042
66160
|
}
|
|
66161
|
+
function isInt64NativeType(nativeType) {
|
|
66162
|
+
if (!nativeType) return false;
|
|
66163
|
+
const normalized = nativeType.toLowerCase();
|
|
66164
|
+
return normalized === "int8" || normalized === "bigint";
|
|
66165
|
+
}
|
|
66043
66166
|
function normalizeLiteralValue(value, nativeType) {
|
|
66044
66167
|
if (value instanceof Date) return value.toISOString();
|
|
66045
66168
|
if (typeof value === "string" && isTemporalNativeType(nativeType)) {
|
|
66046
66169
|
const parsed = new Date(value);
|
|
66047
66170
|
if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();
|
|
66048
66171
|
}
|
|
66172
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && isInt64NativeType(nativeType)) return String(value);
|
|
66049
66173
|
return value;
|
|
66050
66174
|
}
|
|
66051
66175
|
function literalValuesEqual(a, b) {
|
|
@@ -66509,6 +66633,1487 @@ var SqlSchemaIR = class extends SqlSchemaIRNode {
|
|
|
66509
66633
|
return Object.values(this.tables);
|
|
66510
66634
|
}
|
|
66511
66635
|
};
|
|
66636
|
+
/**
|
|
66637
|
+
* Generic Result type for representing success or failure outcomes.
|
|
66638
|
+
*
|
|
66639
|
+
* This is the standard way to return "expected failures" as values rather than
|
|
66640
|
+
* throwing exceptions. See docs/Error Handling.md for the full taxonomy.
|
|
66641
|
+
*
|
|
66642
|
+
* Naming rationale:
|
|
66643
|
+
* - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator
|
|
66644
|
+
* - `NotOk` avoids collision with domain types like "Failure" or "Error"
|
|
66645
|
+
* - `failure` property distinguishes from JS Error semantics
|
|
66646
|
+
*/
|
|
66647
|
+
/**
|
|
66648
|
+
* Result class that implements both Ok and NotOk variants.
|
|
66649
|
+
*/
|
|
66650
|
+
var ResultImpl = class ResultImpl {
|
|
66651
|
+
ok;
|
|
66652
|
+
_value;
|
|
66653
|
+
_failure;
|
|
66654
|
+
constructor(ok, valueOrFailure) {
|
|
66655
|
+
this.ok = ok;
|
|
66656
|
+
if (ok) this._value = valueOrFailure;
|
|
66657
|
+
else this._failure = valueOrFailure;
|
|
66658
|
+
Object.freeze(this);
|
|
66659
|
+
}
|
|
66660
|
+
get value() {
|
|
66661
|
+
if (!this.ok) throw new InternalError("Cannot access value on NotOk result");
|
|
66662
|
+
return this._value;
|
|
66663
|
+
}
|
|
66664
|
+
get failure() {
|
|
66665
|
+
if (this.ok) throw new InternalError("Cannot access failure on Ok result");
|
|
66666
|
+
return this._failure;
|
|
66667
|
+
}
|
|
66668
|
+
/**
|
|
66669
|
+
* Creates a successful result.
|
|
66670
|
+
*/
|
|
66671
|
+
static ok(value) {
|
|
66672
|
+
return blindCast(new ResultImpl(true, value));
|
|
66673
|
+
}
|
|
66674
|
+
/**
|
|
66675
|
+
* Creates an unsuccessful result.
|
|
66676
|
+
*/
|
|
66677
|
+
static notOk(failure) {
|
|
66678
|
+
return blindCast(new ResultImpl(false, failure));
|
|
66679
|
+
}
|
|
66680
|
+
/**
|
|
66681
|
+
* Asserts that this result is Ok and returns the value.
|
|
66682
|
+
* Throws if the result is NotOk.
|
|
66683
|
+
*/
|
|
66684
|
+
assertOk() {
|
|
66685
|
+
if (!this.ok) throw new InternalError("Expected Ok result but got NotOk");
|
|
66686
|
+
return this.value;
|
|
66687
|
+
}
|
|
66688
|
+
/**
|
|
66689
|
+
* Asserts that this result is NotOk and returns the failure.
|
|
66690
|
+
* Throws if the result is Ok.
|
|
66691
|
+
*/
|
|
66692
|
+
assertNotOk() {
|
|
66693
|
+
if (this.ok) throw new InternalError("Expected NotOk result but got Ok");
|
|
66694
|
+
return this.failure;
|
|
66695
|
+
}
|
|
66696
|
+
};
|
|
66697
|
+
/**
|
|
66698
|
+
* Creates a successful result.
|
|
66699
|
+
*/
|
|
66700
|
+
function ok$1(value) {
|
|
66701
|
+
return ResultImpl.ok(value);
|
|
66702
|
+
}
|
|
66703
|
+
/**
|
|
66704
|
+
* Creates an unsuccessful result.
|
|
66705
|
+
*/
|
|
66706
|
+
function notOk(failure) {
|
|
66707
|
+
return ResultImpl.notOk(failure);
|
|
66708
|
+
}
|
|
66709
|
+
/**
|
|
66710
|
+
* Singleton for void success results.
|
|
66711
|
+
* Use this for validation checks that don't produce a value.
|
|
66712
|
+
*/
|
|
66713
|
+
const OK_VOID = ResultImpl.ok(void 0);
|
|
66714
|
+
/**
|
|
66715
|
+
* Returns a successful void result.
|
|
66716
|
+
* Use this for validation checks that don't produce a value.
|
|
66717
|
+
*/
|
|
66718
|
+
function okVoid() {
|
|
66719
|
+
return OK_VOID;
|
|
66720
|
+
}
|
|
66721
|
+
/**
|
|
66722
|
+
* Name of the synthesised namespace bucket the framework parser uses for
|
|
66723
|
+
* top-level declarations that appear outside any `namespace { … }` block.
|
|
66724
|
+
* The double-underscore decoration signals that the identifier is parser-
|
|
66725
|
+
* synthesised and never appears in user-authored PSL source — writing
|
|
66726
|
+
* `namespace __unspecified__ { … }` is a parse error.
|
|
66727
|
+
*
|
|
66728
|
+
* Distinct from the IR sentinel `__unbound__`: the PSL bucket describes
|
|
66729
|
+
* syntactic absence at the parser layer; the IR sentinel describes a late-
|
|
66730
|
+
* bound storage slot at the IR layer. Per-target interpreters decide how
|
|
66731
|
+
* (or whether) to map the PSL bucket to the IR sentinel.
|
|
66732
|
+
*/
|
|
66733
|
+
const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
|
|
66734
|
+
/**
|
|
66735
|
+
* Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over
|
|
66736
|
+
* it. The getters are prototype members (non-enumerable), so spreading or
|
|
66737
|
+
* `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.
|
|
66738
|
+
*/
|
|
66739
|
+
var PslNamespaceNode = class {
|
|
66740
|
+
kind = "namespace";
|
|
66741
|
+
name;
|
|
66742
|
+
entries;
|
|
66743
|
+
span;
|
|
66744
|
+
constructor(init) {
|
|
66745
|
+
this.name = init.name;
|
|
66746
|
+
this.entries = init.entries;
|
|
66747
|
+
this.span = init.span;
|
|
66748
|
+
Object.freeze(this);
|
|
66749
|
+
}
|
|
66750
|
+
get models() {
|
|
66751
|
+
return blindCast(Object.values(this.entries["model"] ?? {}));
|
|
66752
|
+
}
|
|
66753
|
+
get compositeTypes() {
|
|
66754
|
+
return blindCast(Object.values(this.entries["compositeType"] ?? {}));
|
|
66755
|
+
}
|
|
66756
|
+
};
|
|
66757
|
+
/** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */
|
|
66758
|
+
function makePslNamespace(init) {
|
|
66759
|
+
return new PslNamespaceNode(init);
|
|
66760
|
+
}
|
|
66761
|
+
/**
|
|
66762
|
+
* Builds the frozen `entries[kind][name]` container from per-kind arrays.
|
|
66763
|
+
* Built-ins key on their PSL keyword; extension blocks key on their `kind`
|
|
66764
|
+
* discriminator. Call this rather than hand-building the literal.
|
|
66765
|
+
*/
|
|
66766
|
+
function makePslNamespaceEntries(models, compositeTypes, extensionBlocks) {
|
|
66767
|
+
const container = {};
|
|
66768
|
+
if (models.length > 0) {
|
|
66769
|
+
const map = {};
|
|
66770
|
+
for (const m of models) map[m.name] = m;
|
|
66771
|
+
container["model"] = Object.freeze(map);
|
|
66772
|
+
}
|
|
66773
|
+
if (compositeTypes.length > 0) {
|
|
66774
|
+
const map = {};
|
|
66775
|
+
for (const ct of compositeTypes) map[ct.name] = ct;
|
|
66776
|
+
container["compositeType"] = Object.freeze(map);
|
|
66777
|
+
}
|
|
66778
|
+
for (const block of extensionBlocks) {
|
|
66779
|
+
const existing = container[block.kind];
|
|
66780
|
+
const newMap = existing ? blindCast({ ...existing }) : {};
|
|
66781
|
+
newMap[block.name] = block;
|
|
66782
|
+
container[block.kind] = Object.freeze(newMap);
|
|
66783
|
+
}
|
|
66784
|
+
return Object.freeze(container);
|
|
66785
|
+
}
|
|
66786
|
+
/**
|
|
66787
|
+
* A token in the red tree. Unlike the green-layer {@link Token} (kind + text
|
|
66788
|
+
* only), a red token also carries its absolute `offset` within the source and a
|
|
66789
|
+
* link back to its `parent` {@link SyntaxNode}, so a cursor anchored on a token
|
|
66790
|
+
* can walk outward (parent, previous/next token, siblings) without re-scanning
|
|
66791
|
+
* from the document root.
|
|
66792
|
+
*/
|
|
66793
|
+
var SyntaxToken = class {
|
|
66794
|
+
green;
|
|
66795
|
+
kind;
|
|
66796
|
+
text;
|
|
66797
|
+
offset;
|
|
66798
|
+
parent;
|
|
66799
|
+
/** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
|
|
66800
|
+
index;
|
|
66801
|
+
constructor(green, offset, parent, index) {
|
|
66802
|
+
this.green = green;
|
|
66803
|
+
this.kind = green.kind;
|
|
66804
|
+
this.text = green.text;
|
|
66805
|
+
this.offset = offset;
|
|
66806
|
+
this.parent = parent;
|
|
66807
|
+
this.index = index;
|
|
66808
|
+
}
|
|
66809
|
+
get textLength() {
|
|
66810
|
+
return this.text.length;
|
|
66811
|
+
}
|
|
66812
|
+
get endOffset() {
|
|
66813
|
+
return this.offset + this.textLength;
|
|
66814
|
+
}
|
|
66815
|
+
/** Whether `offset` falls within this token, inclusive of both ends. */
|
|
66816
|
+
isInside(offset) {
|
|
66817
|
+
return offset >= this.offset && offset <= this.endOffset;
|
|
66818
|
+
}
|
|
66819
|
+
isOutside(offset) {
|
|
66820
|
+
return !this.isInside(offset);
|
|
66821
|
+
}
|
|
66822
|
+
/** The sibling element immediately after this token within its parent. */
|
|
66823
|
+
get nextSiblingOrToken() {
|
|
66824
|
+
return childAt(this.parent, this.index + 1);
|
|
66825
|
+
}
|
|
66826
|
+
/** The sibling element immediately before this token within its parent. */
|
|
66827
|
+
get prevSiblingOrToken() {
|
|
66828
|
+
return childAt(this.parent, this.index - 1);
|
|
66829
|
+
}
|
|
66830
|
+
/** The next token in document order, crossing node boundaries. */
|
|
66831
|
+
get nextToken() {
|
|
66832
|
+
for (let el = climbingNext(this); el !== void 0; el = climbingNext(el)) {
|
|
66833
|
+
const token = firstToken(el);
|
|
66834
|
+
if (token !== void 0) return token;
|
|
66835
|
+
}
|
|
66836
|
+
}
|
|
66837
|
+
/** The previous token in document order, crossing node boundaries. */
|
|
66838
|
+
get prevToken() {
|
|
66839
|
+
for (let el = climbingPrev(this); el !== void 0; el = climbingPrev(el)) {
|
|
66840
|
+
const token = lastToken(el);
|
|
66841
|
+
if (token !== void 0) return token;
|
|
66842
|
+
}
|
|
66843
|
+
}
|
|
66844
|
+
};
|
|
66845
|
+
var TokenAtOffset = class TokenAtOffset {
|
|
66846
|
+
#state;
|
|
66847
|
+
constructor(state) {
|
|
66848
|
+
this.#state = state;
|
|
66849
|
+
}
|
|
66850
|
+
static none() {
|
|
66851
|
+
return new TokenAtOffset({ kind: "none" });
|
|
66852
|
+
}
|
|
66853
|
+
static single(token) {
|
|
66854
|
+
return new TokenAtOffset({
|
|
66855
|
+
kind: "single",
|
|
66856
|
+
token
|
|
66857
|
+
});
|
|
66858
|
+
}
|
|
66859
|
+
static between(left, right) {
|
|
66860
|
+
return new TokenAtOffset({
|
|
66861
|
+
kind: "between",
|
|
66862
|
+
left,
|
|
66863
|
+
right
|
|
66864
|
+
});
|
|
66865
|
+
}
|
|
66866
|
+
get isEmpty() {
|
|
66867
|
+
return this.#state.kind === "none";
|
|
66868
|
+
}
|
|
66869
|
+
get isBetween() {
|
|
66870
|
+
return this.#state.kind === "between";
|
|
66871
|
+
}
|
|
66872
|
+
leftBiased() {
|
|
66873
|
+
switch (this.#state.kind) {
|
|
66874
|
+
case "none": return;
|
|
66875
|
+
case "single": return this.#state.token;
|
|
66876
|
+
case "between": return this.#state.left;
|
|
66877
|
+
}
|
|
66878
|
+
}
|
|
66879
|
+
rightBiased() {
|
|
66880
|
+
switch (this.#state.kind) {
|
|
66881
|
+
case "none": return;
|
|
66882
|
+
case "single": return this.#state.token;
|
|
66883
|
+
case "between": return this.#state.right;
|
|
66884
|
+
}
|
|
66885
|
+
}
|
|
66886
|
+
};
|
|
66887
|
+
var SyntaxNode = class SyntaxNode {
|
|
66888
|
+
green;
|
|
66889
|
+
offset;
|
|
66890
|
+
parent;
|
|
66891
|
+
/** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
|
|
66892
|
+
index;
|
|
66893
|
+
constructor(green, offset, parent, index) {
|
|
66894
|
+
this.green = green;
|
|
66895
|
+
this.offset = offset;
|
|
66896
|
+
this.parent = parent;
|
|
66897
|
+
this.index = index;
|
|
66898
|
+
}
|
|
66899
|
+
get kind() {
|
|
66900
|
+
return this.green.kind;
|
|
66901
|
+
}
|
|
66902
|
+
get textLength() {
|
|
66903
|
+
return this.green.textLength;
|
|
66904
|
+
}
|
|
66905
|
+
get endOffset() {
|
|
66906
|
+
return this.offset + this.textLength;
|
|
66907
|
+
}
|
|
66908
|
+
/** Whether `offset` falls within this node, inclusive of both ends. */
|
|
66909
|
+
isInside(offset) {
|
|
66910
|
+
return offset >= this.offset && offset <= this.endOffset;
|
|
66911
|
+
}
|
|
66912
|
+
isOutside(offset) {
|
|
66913
|
+
return !this.isInside(offset);
|
|
66914
|
+
}
|
|
66915
|
+
get firstChild() {
|
|
66916
|
+
return childAt(this, 0);
|
|
66917
|
+
}
|
|
66918
|
+
get lastChild() {
|
|
66919
|
+
const len = this.green.children.length;
|
|
66920
|
+
if (len === 0) return void 0;
|
|
66921
|
+
return childAt(this, len - 1);
|
|
66922
|
+
}
|
|
66923
|
+
get nextSibling() {
|
|
66924
|
+
return this.parent === void 0 ? void 0 : childAt(this.parent, this.index + 1);
|
|
66925
|
+
}
|
|
66926
|
+
get prevSibling() {
|
|
66927
|
+
return this.parent === void 0 ? void 0 : childAt(this.parent, this.index - 1);
|
|
66928
|
+
}
|
|
66929
|
+
/** The sibling element immediately after this node within its parent. */
|
|
66930
|
+
get nextSiblingOrToken() {
|
|
66931
|
+
return this.nextSibling;
|
|
66932
|
+
}
|
|
66933
|
+
/** The sibling element immediately before this node within its parent. */
|
|
66934
|
+
get prevSiblingOrToken() {
|
|
66935
|
+
return this.prevSibling;
|
|
66936
|
+
}
|
|
66937
|
+
/** The first token in this subtree (depth-first), or `undefined` if empty. */
|
|
66938
|
+
get firstToken() {
|
|
66939
|
+
return firstToken(this);
|
|
66940
|
+
}
|
|
66941
|
+
/** The last token in this subtree (depth-first), or `undefined` if empty. */
|
|
66942
|
+
get lastToken() {
|
|
66943
|
+
return lastToken(this);
|
|
66944
|
+
}
|
|
66945
|
+
*children() {
|
|
66946
|
+
let offset = this.offset;
|
|
66947
|
+
let index = 0;
|
|
66948
|
+
for (const child of this.green.children) {
|
|
66949
|
+
yield wrapElement(child, offset, this, index);
|
|
66950
|
+
offset += elementTextLength(child);
|
|
66951
|
+
index++;
|
|
66952
|
+
}
|
|
66953
|
+
}
|
|
66954
|
+
*childNodes() {
|
|
66955
|
+
for (const child of this.children()) if (child instanceof SyntaxNode) yield child;
|
|
66956
|
+
}
|
|
66957
|
+
*ancestors() {
|
|
66958
|
+
let current = this.parent;
|
|
66959
|
+
while (current) {
|
|
66960
|
+
yield current;
|
|
66961
|
+
current = current.parent;
|
|
66962
|
+
}
|
|
66963
|
+
}
|
|
66964
|
+
/** The nearest match, testing this node itself before walking its ancestors. */
|
|
66965
|
+
findAncestor(cast) {
|
|
66966
|
+
const self = cast(this);
|
|
66967
|
+
if (self !== void 0) return self;
|
|
66968
|
+
for (const ancestor of this.ancestors()) {
|
|
66969
|
+
const result = cast(ancestor);
|
|
66970
|
+
if (result !== void 0) return result;
|
|
66971
|
+
}
|
|
66972
|
+
}
|
|
66973
|
+
*descendants() {
|
|
66974
|
+
const stack = [this];
|
|
66975
|
+
for (let el = stack.pop(); el !== void 0; el = stack.pop()) {
|
|
66976
|
+
yield el;
|
|
66977
|
+
if (el instanceof SyntaxNode) {
|
|
66978
|
+
const children = Array.from(el.children());
|
|
66979
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
66980
|
+
const child = children[i];
|
|
66981
|
+
if (child !== void 0) stack.push(child);
|
|
66982
|
+
}
|
|
66983
|
+
}
|
|
66984
|
+
}
|
|
66985
|
+
}
|
|
66986
|
+
*tokens() {
|
|
66987
|
+
for (const el of this.descendants()) if (el instanceof SyntaxToken) yield el;
|
|
66988
|
+
}
|
|
66989
|
+
/**
|
|
66990
|
+
* The token(s) at `offset`. The between-two-tokens case (offset exactly on a
|
|
66991
|
+
* token seam) is represented explicitly so callers can left/right bias.
|
|
66992
|
+
*/
|
|
66993
|
+
tokenAtOffset(offset) {
|
|
66994
|
+
return tokenAtOffsetOf(this, offset);
|
|
66995
|
+
}
|
|
66996
|
+
/**
|
|
66997
|
+
* The smallest element fully containing the range `[start, end]`. At a seam
|
|
66998
|
+
* (and for empty ranges) the left-hand element is preferred, matching
|
|
66999
|
+
* {@link containsOffset}'s inclusive span.
|
|
67000
|
+
*/
|
|
67001
|
+
coveringElement(start, end) {
|
|
67002
|
+
let result = this;
|
|
67003
|
+
for (;;) {
|
|
67004
|
+
if (result instanceof SyntaxToken) return result;
|
|
67005
|
+
let next;
|
|
67006
|
+
for (const child of result.children()) if (containsRange(child, start, end)) {
|
|
67007
|
+
next = child;
|
|
67008
|
+
break;
|
|
67009
|
+
}
|
|
67010
|
+
if (next === void 0) return result;
|
|
67011
|
+
result = next;
|
|
67012
|
+
}
|
|
67013
|
+
}
|
|
67014
|
+
};
|
|
67015
|
+
function elementTextLength(el) {
|
|
67016
|
+
return el.type === "token" ? el.text.length : el.textLength;
|
|
67017
|
+
}
|
|
67018
|
+
function elementLength(el) {
|
|
67019
|
+
return el instanceof SyntaxToken ? el.text.length : el.textLength;
|
|
67020
|
+
}
|
|
67021
|
+
/**
|
|
67022
|
+
* Whether `el` contains `offset`. The span is inclusive on both ends so a seam
|
|
67023
|
+
* offset touches both neighbours.
|
|
67024
|
+
*/
|
|
67025
|
+
function containsOffset(el, offset) {
|
|
67026
|
+
const start = el.offset;
|
|
67027
|
+
const len = elementLength(el);
|
|
67028
|
+
return offset >= start && offset <= start + len;
|
|
67029
|
+
}
|
|
67030
|
+
function containsRange(el, start, end) {
|
|
67031
|
+
const elStart = el.offset;
|
|
67032
|
+
const len = elementLength(el);
|
|
67033
|
+
return elStart <= start && end <= elStart + len;
|
|
67034
|
+
}
|
|
67035
|
+
function tokenAtOffsetOf(el, offset) {
|
|
67036
|
+
if (el instanceof SyntaxToken) return TokenAtOffset.single(el);
|
|
67037
|
+
let left;
|
|
67038
|
+
let right;
|
|
67039
|
+
for (const child of el.children()) {
|
|
67040
|
+
if (!containsOffset(child, offset)) continue;
|
|
67041
|
+
if (left === void 0) left = child;
|
|
67042
|
+
else {
|
|
67043
|
+
right = child;
|
|
67044
|
+
break;
|
|
67045
|
+
}
|
|
67046
|
+
}
|
|
67047
|
+
if (left === void 0) return TokenAtOffset.none();
|
|
67048
|
+
if (right === void 0) return tokenAtOffsetOf(left, offset);
|
|
67049
|
+
const leftToken = tokenAtOffsetOf(left, offset).rightBiased();
|
|
67050
|
+
const rightToken = tokenAtOffsetOf(right, offset).leftBiased();
|
|
67051
|
+
if (leftToken !== void 0 && rightToken !== void 0) return TokenAtOffset.between(leftToken, rightToken);
|
|
67052
|
+
if (leftToken !== void 0) return TokenAtOffset.single(leftToken);
|
|
67053
|
+
if (rightToken !== void 0) return TokenAtOffset.single(rightToken);
|
|
67054
|
+
return TokenAtOffset.none();
|
|
67055
|
+
}
|
|
67056
|
+
function firstToken(el) {
|
|
67057
|
+
if (el instanceof SyntaxToken) return el;
|
|
67058
|
+
for (const child of el.children()) {
|
|
67059
|
+
const token = firstToken(child);
|
|
67060
|
+
if (token !== void 0) return token;
|
|
67061
|
+
}
|
|
67062
|
+
}
|
|
67063
|
+
function lastToken(el) {
|
|
67064
|
+
if (el instanceof SyntaxToken) return el;
|
|
67065
|
+
const children = Array.from(el.children());
|
|
67066
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
67067
|
+
const child = children[i];
|
|
67068
|
+
if (child !== void 0) {
|
|
67069
|
+
const token = lastToken(child);
|
|
67070
|
+
if (token !== void 0) return token;
|
|
67071
|
+
}
|
|
67072
|
+
}
|
|
67073
|
+
}
|
|
67074
|
+
function climbingNext(el) {
|
|
67075
|
+
let current = el;
|
|
67076
|
+
for (;;) {
|
|
67077
|
+
const parent = current.parent;
|
|
67078
|
+
if (parent === void 0) return void 0;
|
|
67079
|
+
const sibling = childAt(parent, current.index + 1);
|
|
67080
|
+
if (sibling !== void 0) return sibling;
|
|
67081
|
+
current = parent;
|
|
67082
|
+
}
|
|
67083
|
+
}
|
|
67084
|
+
function climbingPrev(el) {
|
|
67085
|
+
let current = el;
|
|
67086
|
+
for (;;) {
|
|
67087
|
+
const parent = current.parent;
|
|
67088
|
+
if (parent === void 0) return void 0;
|
|
67089
|
+
const sibling = childAt(parent, current.index - 1);
|
|
67090
|
+
if (sibling !== void 0) return sibling;
|
|
67091
|
+
current = parent;
|
|
67092
|
+
}
|
|
67093
|
+
}
|
|
67094
|
+
function wrapElement(green, offset, parent, index) {
|
|
67095
|
+
if (green.type === "token") return new SyntaxToken(green, offset, parent, index);
|
|
67096
|
+
return new SyntaxNode(green, offset, parent, index);
|
|
67097
|
+
}
|
|
67098
|
+
function childAt(node, index) {
|
|
67099
|
+
const children = node.green.children;
|
|
67100
|
+
const target = children[index];
|
|
67101
|
+
if (target === void 0) return void 0;
|
|
67102
|
+
let offset = node.offset;
|
|
67103
|
+
for (let i = 0; i < index; i++) {
|
|
67104
|
+
const child = children[i];
|
|
67105
|
+
if (child !== void 0) offset += elementTextLength(child);
|
|
67106
|
+
}
|
|
67107
|
+
return wrapElement(target, offset, node, index);
|
|
67108
|
+
}
|
|
67109
|
+
function findChildToken(node, kind) {
|
|
67110
|
+
for (const child of node.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) return child;
|
|
67111
|
+
}
|
|
67112
|
+
function findFirstChild(node, cast) {
|
|
67113
|
+
for (const child of node.childNodes()) {
|
|
67114
|
+
const result = cast(child);
|
|
67115
|
+
if (result !== void 0) return result;
|
|
67116
|
+
}
|
|
67117
|
+
}
|
|
67118
|
+
function* filterChildren(node, cast) {
|
|
67119
|
+
for (const child of node.childNodes()) {
|
|
67120
|
+
const result = cast(child);
|
|
67121
|
+
if (result !== void 0) yield result;
|
|
67122
|
+
}
|
|
67123
|
+
}
|
|
67124
|
+
var IdentifierAst = class IdentifierAst {
|
|
67125
|
+
syntax;
|
|
67126
|
+
constructor(syntax) {
|
|
67127
|
+
this.syntax = syntax;
|
|
67128
|
+
}
|
|
67129
|
+
token() {
|
|
67130
|
+
return findChildToken(this.syntax, "Ident");
|
|
67131
|
+
}
|
|
67132
|
+
name() {
|
|
67133
|
+
return this.token()?.text;
|
|
67134
|
+
}
|
|
67135
|
+
static cast(node) {
|
|
67136
|
+
return node.kind === "Identifier" ? new IdentifierAst(node) : void 0;
|
|
67137
|
+
}
|
|
67138
|
+
};
|
|
67139
|
+
/** A namespace-qualified name, e.g. `pgvector.Vector` or `supabase:auth.User`. */
|
|
67140
|
+
var QualifiedNameAst = class QualifiedNameAst {
|
|
67141
|
+
syntax;
|
|
67142
|
+
constructor(syntax) {
|
|
67143
|
+
this.syntax = syntax;
|
|
67144
|
+
}
|
|
67145
|
+
#segmentBefore(boundary) {
|
|
67146
|
+
let found;
|
|
67147
|
+
for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
|
|
67148
|
+
if (segment.syntax.offset >= boundary) break;
|
|
67149
|
+
found = segment;
|
|
67150
|
+
}
|
|
67151
|
+
return found;
|
|
67152
|
+
}
|
|
67153
|
+
#segmentAfter(boundary) {
|
|
67154
|
+
for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) if (segment.syntax.offset > boundary) return segment;
|
|
67155
|
+
}
|
|
67156
|
+
#separatorCount(kind) {
|
|
67157
|
+
let count = 0;
|
|
67158
|
+
for (const child of this.syntax.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) count++;
|
|
67159
|
+
return count;
|
|
67160
|
+
}
|
|
67161
|
+
colon() {
|
|
67162
|
+
return findChildToken(this.syntax, "Colon");
|
|
67163
|
+
}
|
|
67164
|
+
dot() {
|
|
67165
|
+
return findChildToken(this.syntax, "Dot");
|
|
67166
|
+
}
|
|
67167
|
+
space() {
|
|
67168
|
+
const colon = this.colon();
|
|
67169
|
+
if (!colon) return void 0;
|
|
67170
|
+
return this.#segmentBefore(colon.offset);
|
|
67171
|
+
}
|
|
67172
|
+
namespace() {
|
|
67173
|
+
const dot = this.dot();
|
|
67174
|
+
if (!dot) return void 0;
|
|
67175
|
+
return this.#segmentBefore(dot.offset);
|
|
67176
|
+
}
|
|
67177
|
+
identifier() {
|
|
67178
|
+
const dot = this.dot();
|
|
67179
|
+
if (dot) return this.#segmentAfter(dot.offset);
|
|
67180
|
+
const colon = this.colon();
|
|
67181
|
+
if (colon) return this.#segmentAfter(colon.offset);
|
|
67182
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
67183
|
+
}
|
|
67184
|
+
/**
|
|
67185
|
+
* Every identifier segment, in source order. A bare `Vector` yields
|
|
67186
|
+
* `['Vector']`; a qualified `pgvector.Vector` yields `['pgvector', 'Vector']`.
|
|
67187
|
+
*/
|
|
67188
|
+
path() {
|
|
67189
|
+
const segments = [];
|
|
67190
|
+
for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
|
|
67191
|
+
const text = segment.token()?.text;
|
|
67192
|
+
if (text !== void 0) segments.push(text);
|
|
67193
|
+
}
|
|
67194
|
+
return segments;
|
|
67195
|
+
}
|
|
67196
|
+
/** True iff this is a single unqualified identifier whose text equals `name`. */
|
|
67197
|
+
isSimpleName(name) {
|
|
67198
|
+
if (this.dot() !== void 0 || this.colon() !== void 0) return false;
|
|
67199
|
+
return this.identifier()?.token()?.text === name;
|
|
67200
|
+
}
|
|
67201
|
+
/**
|
|
67202
|
+
* Flags a malformed name with more qualifier segments than allowed (a second
|
|
67203
|
+
* `:`-space or a second `.`-namespace).
|
|
67204
|
+
*/
|
|
67205
|
+
isOverQualified() {
|
|
67206
|
+
return this.#separatorCount("Dot") > 1 || this.#separatorCount("Colon") > 1;
|
|
67207
|
+
}
|
|
67208
|
+
static cast(node) {
|
|
67209
|
+
return node.kind === "QualifiedName" ? new QualifiedNameAst(node) : void 0;
|
|
67210
|
+
}
|
|
67211
|
+
};
|
|
67212
|
+
var FunctionCallAst = class FunctionCallAst {
|
|
67213
|
+
syntax;
|
|
67214
|
+
constructor(syntax) {
|
|
67215
|
+
this.syntax = syntax;
|
|
67216
|
+
}
|
|
67217
|
+
/** The qualified-name callee, or `undefined` when identifier segments sit directly under the node. */
|
|
67218
|
+
name() {
|
|
67219
|
+
return findFirstChild(this.syntax, QualifiedNameAst.cast);
|
|
67220
|
+
}
|
|
67221
|
+
/**
|
|
67222
|
+
* The dotted call path, in source order. A bare `Vector(…)` yields
|
|
67223
|
+
* `['Vector']`; a namespace-qualified `pgvector.Vector(…)` yields
|
|
67224
|
+
* `['pgvector', 'Vector']`. Empty when the call carries no identifier.
|
|
67225
|
+
*/
|
|
67226
|
+
path() {
|
|
67227
|
+
const qualified = this.name();
|
|
67228
|
+
const segments = [];
|
|
67229
|
+
for (const segment of filterChildren(qualified?.syntax ?? this.syntax, IdentifierAst.cast)) {
|
|
67230
|
+
const text = segment.token()?.text;
|
|
67231
|
+
if (text !== void 0) segments.push(text);
|
|
67232
|
+
}
|
|
67233
|
+
return segments;
|
|
67234
|
+
}
|
|
67235
|
+
lparen() {
|
|
67236
|
+
return findChildToken(this.syntax, "LParen");
|
|
67237
|
+
}
|
|
67238
|
+
rparen() {
|
|
67239
|
+
return findChildToken(this.syntax, "RParen");
|
|
67240
|
+
}
|
|
67241
|
+
*args() {
|
|
67242
|
+
yield* filterChildren(this.syntax, AttributeArgAst.cast);
|
|
67243
|
+
}
|
|
67244
|
+
static cast(node) {
|
|
67245
|
+
return node.kind === "FunctionCall" ? new FunctionCallAst(node) : void 0;
|
|
67246
|
+
}
|
|
67247
|
+
};
|
|
67248
|
+
var ArrayLiteralAst = class ArrayLiteralAst {
|
|
67249
|
+
syntax;
|
|
67250
|
+
constructor(syntax) {
|
|
67251
|
+
this.syntax = syntax;
|
|
67252
|
+
}
|
|
67253
|
+
lbracket() {
|
|
67254
|
+
return findChildToken(this.syntax, "LBracket");
|
|
67255
|
+
}
|
|
67256
|
+
rbracket() {
|
|
67257
|
+
return findChildToken(this.syntax, "RBracket");
|
|
67258
|
+
}
|
|
67259
|
+
*elements() {
|
|
67260
|
+
yield* filterChildren(this.syntax, castExpression);
|
|
67261
|
+
}
|
|
67262
|
+
static cast(node) {
|
|
67263
|
+
return node.kind === "ArrayLiteral" ? new ArrayLiteralAst(node) : void 0;
|
|
67264
|
+
}
|
|
67265
|
+
};
|
|
67266
|
+
const HEX = /^[0-9a-fA-F]+$/;
|
|
67267
|
+
function decodeFixedHex(raw, start, width) {
|
|
67268
|
+
if (start + width > raw.length) return void 0;
|
|
67269
|
+
const hex = raw.slice(start, start + width);
|
|
67270
|
+
if (!HEX.test(hex)) return void 0;
|
|
67271
|
+
return String.fromCharCode(Number.parseInt(hex, 16));
|
|
67272
|
+
}
|
|
67273
|
+
function decodeStringLiteral(raw) {
|
|
67274
|
+
let out = "";
|
|
67275
|
+
let i = 0;
|
|
67276
|
+
while (i < raw.length) {
|
|
67277
|
+
const ch = raw.charAt(i);
|
|
67278
|
+
if (ch !== "\\" || i + 1 >= raw.length) {
|
|
67279
|
+
out += ch;
|
|
67280
|
+
i++;
|
|
67281
|
+
continue;
|
|
67282
|
+
}
|
|
67283
|
+
const next = raw.charAt(i + 1);
|
|
67284
|
+
switch (next) {
|
|
67285
|
+
case "n":
|
|
67286
|
+
out += "\n";
|
|
67287
|
+
i += 2;
|
|
67288
|
+
continue;
|
|
67289
|
+
case "r":
|
|
67290
|
+
out += "\r";
|
|
67291
|
+
i += 2;
|
|
67292
|
+
continue;
|
|
67293
|
+
case "t":
|
|
67294
|
+
out += " ";
|
|
67295
|
+
i += 2;
|
|
67296
|
+
continue;
|
|
67297
|
+
case "\"":
|
|
67298
|
+
out += "\"";
|
|
67299
|
+
i += 2;
|
|
67300
|
+
continue;
|
|
67301
|
+
case "'":
|
|
67302
|
+
out += "'";
|
|
67303
|
+
i += 2;
|
|
67304
|
+
continue;
|
|
67305
|
+
case "\\":
|
|
67306
|
+
out += "\\";
|
|
67307
|
+
i += 2;
|
|
67308
|
+
continue;
|
|
67309
|
+
case "x": {
|
|
67310
|
+
const decoded = decodeFixedHex(raw, i + 2, 2);
|
|
67311
|
+
if (decoded === void 0) {
|
|
67312
|
+
out += "\\x";
|
|
67313
|
+
i += 2;
|
|
67314
|
+
continue;
|
|
67315
|
+
}
|
|
67316
|
+
out += decoded;
|
|
67317
|
+
i += 4;
|
|
67318
|
+
continue;
|
|
67319
|
+
}
|
|
67320
|
+
case "u": {
|
|
67321
|
+
const decoded = decodeFixedHex(raw, i + 2, 4);
|
|
67322
|
+
if (decoded === void 0) {
|
|
67323
|
+
out += "\\u";
|
|
67324
|
+
i += 2;
|
|
67325
|
+
continue;
|
|
67326
|
+
}
|
|
67327
|
+
out += decoded;
|
|
67328
|
+
i += 6;
|
|
67329
|
+
continue;
|
|
67330
|
+
}
|
|
67331
|
+
default:
|
|
67332
|
+
out += `\\${next}`;
|
|
67333
|
+
i += 2;
|
|
67334
|
+
continue;
|
|
67335
|
+
}
|
|
67336
|
+
}
|
|
67337
|
+
return out;
|
|
67338
|
+
}
|
|
67339
|
+
var StringLiteralExprAst = class StringLiteralExprAst {
|
|
67340
|
+
syntax;
|
|
67341
|
+
constructor(syntax) {
|
|
67342
|
+
this.syntax = syntax;
|
|
67343
|
+
}
|
|
67344
|
+
token() {
|
|
67345
|
+
return findChildToken(this.syntax, "StringLiteral");
|
|
67346
|
+
}
|
|
67347
|
+
value() {
|
|
67348
|
+
const tok = this.token();
|
|
67349
|
+
if (!tok) return void 0;
|
|
67350
|
+
return decodeStringLiteral(tok.text.slice(1, -1));
|
|
67351
|
+
}
|
|
67352
|
+
static cast(node) {
|
|
67353
|
+
return node.kind === "StringLiteralExpr" ? new StringLiteralExprAst(node) : void 0;
|
|
67354
|
+
}
|
|
67355
|
+
};
|
|
67356
|
+
var NumberLiteralExprAst = class NumberLiteralExprAst {
|
|
67357
|
+
syntax;
|
|
67358
|
+
constructor(syntax) {
|
|
67359
|
+
this.syntax = syntax;
|
|
67360
|
+
}
|
|
67361
|
+
token() {
|
|
67362
|
+
return findChildToken(this.syntax, "NumberLiteral");
|
|
67363
|
+
}
|
|
67364
|
+
value() {
|
|
67365
|
+
const tok = this.token();
|
|
67366
|
+
if (!tok) return void 0;
|
|
67367
|
+
return Number(tok.text);
|
|
67368
|
+
}
|
|
67369
|
+
static cast(node) {
|
|
67370
|
+
return node.kind === "NumberLiteralExpr" ? new NumberLiteralExprAst(node) : void 0;
|
|
67371
|
+
}
|
|
67372
|
+
};
|
|
67373
|
+
var BooleanLiteralExprAst = class BooleanLiteralExprAst {
|
|
67374
|
+
syntax;
|
|
67375
|
+
constructor(syntax) {
|
|
67376
|
+
this.syntax = syntax;
|
|
67377
|
+
}
|
|
67378
|
+
token() {
|
|
67379
|
+
return findChildToken(this.syntax, "Ident");
|
|
67380
|
+
}
|
|
67381
|
+
value() {
|
|
67382
|
+
const tok = this.token();
|
|
67383
|
+
if (!tok) return void 0;
|
|
67384
|
+
if (tok.text === "true") return true;
|
|
67385
|
+
if (tok.text === "false") return false;
|
|
67386
|
+
}
|
|
67387
|
+
static cast(node) {
|
|
67388
|
+
return node.kind === "BooleanLiteralExpr" ? new BooleanLiteralExprAst(node) : void 0;
|
|
67389
|
+
}
|
|
67390
|
+
};
|
|
67391
|
+
var ObjectLiteralExprAst = class ObjectLiteralExprAst {
|
|
67392
|
+
syntax;
|
|
67393
|
+
constructor(syntax) {
|
|
67394
|
+
this.syntax = syntax;
|
|
67395
|
+
}
|
|
67396
|
+
lbrace() {
|
|
67397
|
+
return findChildToken(this.syntax, "LBrace");
|
|
67398
|
+
}
|
|
67399
|
+
rbrace() {
|
|
67400
|
+
return findChildToken(this.syntax, "RBrace");
|
|
67401
|
+
}
|
|
67402
|
+
*fields() {
|
|
67403
|
+
yield* filterChildren(this.syntax, ObjectFieldAst.cast);
|
|
67404
|
+
}
|
|
67405
|
+
static cast(node) {
|
|
67406
|
+
return node.kind === "ObjectLiteralExpr" ? new ObjectLiteralExprAst(node) : void 0;
|
|
67407
|
+
}
|
|
67408
|
+
};
|
|
67409
|
+
var ObjectFieldAst = class ObjectFieldAst {
|
|
67410
|
+
syntax;
|
|
67411
|
+
constructor(syntax) {
|
|
67412
|
+
this.syntax = syntax;
|
|
67413
|
+
}
|
|
67414
|
+
key() {
|
|
67415
|
+
for (const child of this.syntax.children()) {
|
|
67416
|
+
if (!(child instanceof SyntaxNode)) {
|
|
67417
|
+
if (child.kind === "Colon") break;
|
|
67418
|
+
continue;
|
|
67419
|
+
}
|
|
67420
|
+
return IdentifierAst.cast(child);
|
|
67421
|
+
}
|
|
67422
|
+
}
|
|
67423
|
+
/**
|
|
67424
|
+
* The field's logical key name, unquoted. An identifier key (`length:`) yields
|
|
67425
|
+
* its text; a string-literal key (`"length":`) yields the decoded string.
|
|
67426
|
+
* `undefined` when the field carries no key node.
|
|
67427
|
+
*/
|
|
67428
|
+
keyName() {
|
|
67429
|
+
for (const child of this.syntax.children()) {
|
|
67430
|
+
if (!(child instanceof SyntaxNode)) {
|
|
67431
|
+
if (child.kind === "Colon") break;
|
|
67432
|
+
continue;
|
|
67433
|
+
}
|
|
67434
|
+
const identifier = IdentifierAst.cast(child);
|
|
67435
|
+
if (identifier) return identifier.token()?.text;
|
|
67436
|
+
const stringKey = StringLiteralExprAst.cast(child);
|
|
67437
|
+
if (stringKey) return stringKey.value();
|
|
67438
|
+
return;
|
|
67439
|
+
}
|
|
67440
|
+
}
|
|
67441
|
+
colon() {
|
|
67442
|
+
return findChildToken(this.syntax, "Colon");
|
|
67443
|
+
}
|
|
67444
|
+
value() {
|
|
67445
|
+
if (this.colon()) {
|
|
67446
|
+
let pastColon = false;
|
|
67447
|
+
for (const child of this.syntax.children()) {
|
|
67448
|
+
if (!(child instanceof SyntaxNode)) {
|
|
67449
|
+
if (child.kind === "Colon") pastColon = true;
|
|
67450
|
+
continue;
|
|
67451
|
+
}
|
|
67452
|
+
if (pastColon) {
|
|
67453
|
+
const expr = castExpression(child);
|
|
67454
|
+
if (expr) return expr;
|
|
67455
|
+
}
|
|
67456
|
+
}
|
|
67457
|
+
return;
|
|
67458
|
+
}
|
|
67459
|
+
return findFirstChild(this.syntax, castExpression);
|
|
67460
|
+
}
|
|
67461
|
+
static cast(node) {
|
|
67462
|
+
return node.kind === "ObjectField" ? new ObjectFieldAst(node) : void 0;
|
|
67463
|
+
}
|
|
67464
|
+
};
|
|
67465
|
+
function castExpression(node) {
|
|
67466
|
+
return FunctionCallAst.cast(node) ?? ArrayLiteralAst.cast(node) ?? StringLiteralExprAst.cast(node) ?? NumberLiteralExprAst.cast(node) ?? BooleanLiteralExprAst.cast(node) ?? ObjectLiteralExprAst.cast(node) ?? IdentifierAst.cast(node);
|
|
67467
|
+
}
|
|
67468
|
+
var AttributeArgAst = class AttributeArgAst {
|
|
67469
|
+
syntax;
|
|
67470
|
+
constructor(syntax) {
|
|
67471
|
+
this.syntax = syntax;
|
|
67472
|
+
}
|
|
67473
|
+
name() {
|
|
67474
|
+
if (!this.colon()) return void 0;
|
|
67475
|
+
return findFirstChild(this.syntax, IdentifierAst.cast);
|
|
67476
|
+
}
|
|
67477
|
+
colon() {
|
|
67478
|
+
return findChildToken(this.syntax, "Colon");
|
|
67479
|
+
}
|
|
67480
|
+
value() {
|
|
67481
|
+
if (this.colon()) {
|
|
67482
|
+
let pastColon = false;
|
|
67483
|
+
for (const child of this.syntax.children()) {
|
|
67484
|
+
if (!(child instanceof SyntaxNode)) {
|
|
67485
|
+
if (child.kind === "Colon") pastColon = true;
|
|
67486
|
+
continue;
|
|
67487
|
+
}
|
|
67488
|
+
if (pastColon) {
|
|
67489
|
+
const expr = castExpression(child);
|
|
67490
|
+
if (expr) return expr;
|
|
67491
|
+
}
|
|
67492
|
+
}
|
|
67493
|
+
return;
|
|
67494
|
+
}
|
|
67495
|
+
return findFirstChild(this.syntax, castExpression);
|
|
67496
|
+
}
|
|
67497
|
+
static cast(node) {
|
|
67498
|
+
return node.kind === "AttributeArg" ? new AttributeArgAst(node) : void 0;
|
|
67499
|
+
}
|
|
67500
|
+
};
|
|
67501
|
+
function blockAttribute(name, config) {
|
|
67502
|
+
return {
|
|
67503
|
+
level: "block",
|
|
67504
|
+
name,
|
|
67505
|
+
positional: config.positional ?? [],
|
|
67506
|
+
named: config.named ?? {},
|
|
67507
|
+
...config.refine !== void 0 ? { refine: config.refine } : {}
|
|
67508
|
+
};
|
|
67509
|
+
}
|
|
67510
|
+
function nodePslSpan(node, sourceFile) {
|
|
67511
|
+
const start = node.offset;
|
|
67512
|
+
const end = start + node.green.textLength;
|
|
67513
|
+
return {
|
|
67514
|
+
start: offsetToPslPosition(start, sourceFile),
|
|
67515
|
+
end: offsetToPslPosition(end, sourceFile)
|
|
67516
|
+
};
|
|
67517
|
+
}
|
|
67518
|
+
function offsetToPslPosition(offset, sourceFile) {
|
|
67519
|
+
const position = sourceFile.positionAt(offset);
|
|
67520
|
+
return {
|
|
67521
|
+
offset,
|
|
67522
|
+
line: position.line + 1,
|
|
67523
|
+
column: position.character + 1
|
|
67524
|
+
};
|
|
67525
|
+
}
|
|
67526
|
+
const ATTRIBUTE_DIAGNOSTIC_CODE = "PSL_INVALID_ATTRIBUTE_SYNTAX";
|
|
67527
|
+
function leafDiagnostic(ctx, node, message, code = ATTRIBUTE_DIAGNOSTIC_CODE) {
|
|
67528
|
+
return {
|
|
67529
|
+
code,
|
|
67530
|
+
message,
|
|
67531
|
+
sourceId: ctx.sourceId,
|
|
67532
|
+
span: nodePslSpan(node.syntax, ctx.sourceFile)
|
|
67533
|
+
};
|
|
67534
|
+
}
|
|
67535
|
+
function bool() {
|
|
67536
|
+
return {
|
|
67537
|
+
kind: "bool",
|
|
67538
|
+
label: "boolean",
|
|
67539
|
+
parse: (arg, ctx) => {
|
|
67540
|
+
const literal = BooleanLiteralExprAst.cast(arg.syntax);
|
|
67541
|
+
if (literal !== void 0) {
|
|
67542
|
+
const value = literal.value();
|
|
67543
|
+
if (value !== void 0) return ok$1(value);
|
|
67544
|
+
}
|
|
67545
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected a boolean literal")]);
|
|
67546
|
+
}
|
|
67547
|
+
};
|
|
67548
|
+
}
|
|
67549
|
+
function entityRef() {
|
|
67550
|
+
return {
|
|
67551
|
+
kind: "entityRef",
|
|
67552
|
+
label: "model name",
|
|
67553
|
+
parse: (arg, ctx) => {
|
|
67554
|
+
const identifier = IdentifierAst.cast(arg.syntax);
|
|
67555
|
+
if (identifier === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a model name")]);
|
|
67556
|
+
const name = identifier.name();
|
|
67557
|
+
if (name === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a model name")]);
|
|
67558
|
+
return ok$1(name);
|
|
67559
|
+
}
|
|
67560
|
+
};
|
|
67561
|
+
}
|
|
67562
|
+
function parseFieldName(arg, ctx, model) {
|
|
67563
|
+
const identifier = IdentifierAst.cast(arg.syntax);
|
|
67564
|
+
if (identifier === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a field name")]);
|
|
67565
|
+
const name = identifier.name();
|
|
67566
|
+
if (name === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a field name")]);
|
|
67567
|
+
if (model !== void 0 && !Object.hasOwn(model.fields, name)) return notOk([leafDiagnostic(ctx, arg, `Field "${name}" does not exist on model "${model.name}"`)]);
|
|
67568
|
+
return ok$1(name);
|
|
67569
|
+
}
|
|
67570
|
+
function fieldRef() {
|
|
67571
|
+
return {
|
|
67572
|
+
kind: "fieldRef",
|
|
67573
|
+
label: "field name",
|
|
67574
|
+
parse: (arg, ctx) => parseFieldName(arg, ctx, ctx.selfModel)
|
|
67575
|
+
};
|
|
67576
|
+
}
|
|
67577
|
+
function referencedFieldRef() {
|
|
67578
|
+
return {
|
|
67579
|
+
kind: "referencedFieldRef",
|
|
67580
|
+
label: "field name",
|
|
67581
|
+
parse: (arg, ctx) => parseFieldName(arg, ctx, ctx.resolveReferencedModel())
|
|
67582
|
+
};
|
|
67583
|
+
}
|
|
67584
|
+
function interpretArgs(args, spec, ctx, span) {
|
|
67585
|
+
const diagnostics = [];
|
|
67586
|
+
const output = {};
|
|
67587
|
+
const seen = /* @__PURE__ */ new Set();
|
|
67588
|
+
let positionalSlot = 0;
|
|
67589
|
+
let reportedExcess = false;
|
|
67590
|
+
for (const arg of args) {
|
|
67591
|
+
const name = arg.name()?.name();
|
|
67592
|
+
let key;
|
|
67593
|
+
let param;
|
|
67594
|
+
if (name === void 0) {
|
|
67595
|
+
const posParam = spec.positional[positionalSlot];
|
|
67596
|
+
if (posParam === void 0) {
|
|
67597
|
+
if (!reportedExcess) {
|
|
67598
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" received too many positional arguments`, ctx, span));
|
|
67599
|
+
reportedExcess = true;
|
|
67600
|
+
}
|
|
67601
|
+
continue;
|
|
67602
|
+
}
|
|
67603
|
+
positionalSlot += 1;
|
|
67604
|
+
key = posParam.key;
|
|
67605
|
+
param = posParam.type;
|
|
67606
|
+
} else {
|
|
67607
|
+
const namedParam = Object.hasOwn(spec.named, name) ? spec.named[name] : void 0;
|
|
67608
|
+
if (namedParam === void 0) {
|
|
67609
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" received unknown argument "${name}"`, ctx, nodePslSpan(arg.syntax, ctx.sourceFile)));
|
|
67610
|
+
continue;
|
|
67611
|
+
}
|
|
67612
|
+
key = name;
|
|
67613
|
+
param = namedParam;
|
|
67614
|
+
}
|
|
67615
|
+
if (seen.has(key)) {
|
|
67616
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" received duplicate argument "${key}"`, ctx, nodePslSpan(arg.syntax, ctx.sourceFile)));
|
|
67617
|
+
continue;
|
|
67618
|
+
}
|
|
67619
|
+
seen.add(key);
|
|
67620
|
+
const result = parseArgValue(arg, param, ctx, diagnostics);
|
|
67621
|
+
if (result.ok) output[key] = result.value;
|
|
67622
|
+
}
|
|
67623
|
+
const finalized = /* @__PURE__ */ new Set();
|
|
67624
|
+
const finalizeAbsentKey = (key, positionalParam, namedParam) => {
|
|
67625
|
+
if (finalized.has(key) || seen.has(key)) return;
|
|
67626
|
+
finalized.add(key);
|
|
67627
|
+
const effective = namedParam ?? positionalParam;
|
|
67628
|
+
if (effective === void 0) return;
|
|
67629
|
+
if (isOptionalArgType(effective)) {
|
|
67630
|
+
if (effective.hasDefault) output[key] = effective.defaultValue;
|
|
67631
|
+
return;
|
|
67632
|
+
}
|
|
67633
|
+
diagnostics.push(diagnostic(`Attribute "${spec.name}" is missing required argument "${key}"`, ctx, span));
|
|
67634
|
+
};
|
|
67635
|
+
for (const param of spec.positional) {
|
|
67636
|
+
const namedParam = Object.hasOwn(spec.named, param.key) ? spec.named[param.key] : void 0;
|
|
67637
|
+
finalizeAbsentKey(param.key, param.type, namedParam);
|
|
67638
|
+
}
|
|
67639
|
+
for (const key of Object.keys(spec.named)) finalizeAbsentKey(key, void 0, spec.named[key]);
|
|
67640
|
+
if (diagnostics.length > 0) return notOk(diagnostics);
|
|
67641
|
+
return ok$1(output);
|
|
67642
|
+
}
|
|
67643
|
+
function parseArgValue(arg, argType, ctx, diagnostics) {
|
|
67644
|
+
const value = arg.value();
|
|
67645
|
+
if (value === void 0) {
|
|
67646
|
+
const missing = diagnostic("Attribute argument is missing a value", ctx, nodePslSpan(arg.syntax, ctx.sourceFile));
|
|
67647
|
+
diagnostics.push(missing);
|
|
67648
|
+
return notOk([missing]);
|
|
67649
|
+
}
|
|
67650
|
+
const result = argType.parse(value, ctx);
|
|
67651
|
+
if (!result.ok) for (const failure of result.failure) diagnostics.push(failure);
|
|
67652
|
+
return result;
|
|
67653
|
+
}
|
|
67654
|
+
function isOptionalArgType(param) {
|
|
67655
|
+
return "optional" in param && param.optional === true;
|
|
67656
|
+
}
|
|
67657
|
+
function diagnostic(message, ctx, span) {
|
|
67658
|
+
return {
|
|
67659
|
+
code: ATTRIBUTE_DIAGNOSTIC_CODE,
|
|
67660
|
+
message,
|
|
67661
|
+
sourceId: ctx.sourceId,
|
|
67662
|
+
span
|
|
67663
|
+
};
|
|
67664
|
+
}
|
|
67665
|
+
function funcCall(name, sig) {
|
|
67666
|
+
return {
|
|
67667
|
+
kind: "funcCall",
|
|
67668
|
+
label: `${name}()`,
|
|
67669
|
+
name,
|
|
67670
|
+
signature: sig,
|
|
67671
|
+
parse: (arg, ctx) => {
|
|
67672
|
+
const guard = matchCallee(arg, name, ctx);
|
|
67673
|
+
if (!guard.ok) return guard;
|
|
67674
|
+
const span = nodePslSpan(guard.value.syntax, ctx.sourceFile);
|
|
67675
|
+
const bound = interpretArgs(guard.value.args(), {
|
|
67676
|
+
name,
|
|
67677
|
+
positional: sig.positional ?? [],
|
|
67678
|
+
named: sig.named ?? {}
|
|
67679
|
+
}, ctx, span);
|
|
67680
|
+
if (!bound.ok) return notOk(bound.failure);
|
|
67681
|
+
return ok$1({
|
|
67682
|
+
fn: name,
|
|
67683
|
+
span,
|
|
67684
|
+
args: bound.value
|
|
67685
|
+
});
|
|
67686
|
+
}
|
|
67687
|
+
};
|
|
67688
|
+
}
|
|
67689
|
+
function matchCallee(arg, name, ctx) {
|
|
67690
|
+
const call = FunctionCallAst.cast(arg.syntax);
|
|
67691
|
+
if (call === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
|
|
67692
|
+
const qname = call.name();
|
|
67693
|
+
if (qname === void 0 || qname.dot() !== void 0 || qname.colon() !== void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
|
|
67694
|
+
const calleeName = qname.identifier()?.token()?.text;
|
|
67695
|
+
if (calleeName === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected a function call")]);
|
|
67696
|
+
if (calleeName !== name) return notOk([leafDiagnostic(ctx, arg, `Expected ${name}()`)]);
|
|
67697
|
+
return ok$1(call);
|
|
67698
|
+
}
|
|
67699
|
+
function identifier(name) {
|
|
67700
|
+
return {
|
|
67701
|
+
kind: "identifier",
|
|
67702
|
+
label: name,
|
|
67703
|
+
name,
|
|
67704
|
+
parse: (arg, ctx) => {
|
|
67705
|
+
const identifier = IdentifierAst.cast(arg.syntax);
|
|
67706
|
+
if (identifier !== void 0 && identifier.name() === name) return ok$1(name);
|
|
67707
|
+
return notOk([leafDiagnostic(ctx, arg, `Expected ${name}`)]);
|
|
67708
|
+
}
|
|
67709
|
+
};
|
|
67710
|
+
}
|
|
67711
|
+
function int(opts) {
|
|
67712
|
+
const min = opts?.min;
|
|
67713
|
+
const max = opts?.max;
|
|
67714
|
+
return {
|
|
67715
|
+
kind: "int",
|
|
67716
|
+
label: "integer",
|
|
67717
|
+
...min === void 0 ? {} : { min },
|
|
67718
|
+
...max === void 0 ? {} : { max },
|
|
67719
|
+
parse: (arg, ctx) => {
|
|
67720
|
+
const literal = NumberLiteralExprAst.cast(arg.syntax);
|
|
67721
|
+
if (literal !== void 0) {
|
|
67722
|
+
const value = literal.value();
|
|
67723
|
+
if (value !== void 0 && Number.isInteger(value)) {
|
|
67724
|
+
if ((min === void 0 || value >= min) && (max === void 0 || value <= max)) return ok$1(value);
|
|
67725
|
+
return notOk([leafDiagnostic(ctx, arg, rangeMessage(min, max))]);
|
|
67726
|
+
}
|
|
67727
|
+
}
|
|
67728
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected an integer literal")]);
|
|
67729
|
+
}
|
|
67730
|
+
};
|
|
67731
|
+
}
|
|
67732
|
+
function rangeMessage(min, max) {
|
|
67733
|
+
if (min !== void 0 && max !== void 0) return `Expected an integer between ${min} and ${max}`;
|
|
67734
|
+
if (min !== void 0) return `Expected an integer greater than or equal to ${min}`;
|
|
67735
|
+
return `Expected an integer less than or equal to ${max}`;
|
|
67736
|
+
}
|
|
67737
|
+
function list(of, opts) {
|
|
67738
|
+
const allowEmpty = opts?.allowEmpty ?? true;
|
|
67739
|
+
const unique = opts?.unique ?? false;
|
|
67740
|
+
return {
|
|
67741
|
+
kind: "list",
|
|
67742
|
+
label: `${of.label}[]`,
|
|
67743
|
+
of,
|
|
67744
|
+
allowEmpty,
|
|
67745
|
+
unique,
|
|
67746
|
+
parse: (arg, ctx) => {
|
|
67747
|
+
const literal = ArrayLiteralAst.cast(arg.syntax);
|
|
67748
|
+
if (literal === void 0) return notOk([leafDiagnostic(ctx, arg, `Expected a list of ${of.label}`)]);
|
|
67749
|
+
const diagnostics = [];
|
|
67750
|
+
const parsed = [];
|
|
67751
|
+
let count = 0;
|
|
67752
|
+
for (const element of literal.elements()) {
|
|
67753
|
+
count += 1;
|
|
67754
|
+
const result = of.parse(element, ctx);
|
|
67755
|
+
if (result.ok) parsed.push({
|
|
67756
|
+
node: element,
|
|
67757
|
+
value: result.value
|
|
67758
|
+
});
|
|
67759
|
+
else diagnostics.push(...result.failure);
|
|
67760
|
+
}
|
|
67761
|
+
if (!allowEmpty && count === 0) diagnostics.push(leafDiagnostic(ctx, arg, "Expected a non-empty list"));
|
|
67762
|
+
if (unique) {
|
|
67763
|
+
const seen = /* @__PURE__ */ new Set();
|
|
67764
|
+
for (const { node, value } of parsed) if (seen.has(value)) diagnostics.push(leafDiagnostic(ctx, node, "Duplicate list entry"));
|
|
67765
|
+
else seen.add(value);
|
|
67766
|
+
}
|
|
67767
|
+
if (diagnostics.length > 0) return notOk(diagnostics);
|
|
67768
|
+
return ok$1(parsed.map((entry) => entry.value));
|
|
67769
|
+
}
|
|
67770
|
+
};
|
|
67771
|
+
}
|
|
67772
|
+
function num(value) {
|
|
67773
|
+
if (value === void 0) return {
|
|
67774
|
+
kind: "num",
|
|
67775
|
+
label: "number",
|
|
67776
|
+
value: void 0,
|
|
67777
|
+
parse: (arg, ctx) => {
|
|
67778
|
+
const literal = NumberLiteralExprAst.cast(arg.syntax);
|
|
67779
|
+
if (literal !== void 0) {
|
|
67780
|
+
const parsed = literal.value();
|
|
67781
|
+
if (parsed !== void 0) return ok$1(parsed);
|
|
67782
|
+
}
|
|
67783
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected a number literal")]);
|
|
67784
|
+
}
|
|
67785
|
+
};
|
|
67786
|
+
return {
|
|
67787
|
+
kind: "num",
|
|
67788
|
+
label: String(value),
|
|
67789
|
+
value,
|
|
67790
|
+
parse: (arg, ctx) => {
|
|
67791
|
+
const literal = NumberLiteralExprAst.cast(arg.syntax);
|
|
67792
|
+
if (literal !== void 0) {
|
|
67793
|
+
if (literal.value() === value) return ok$1(value);
|
|
67794
|
+
}
|
|
67795
|
+
return notOk([leafDiagnostic(ctx, arg, `Expected ${value}`)]);
|
|
67796
|
+
}
|
|
67797
|
+
};
|
|
67798
|
+
}
|
|
67799
|
+
function oneOf(...alts) {
|
|
67800
|
+
const label = alts.map((alt) => alt.label).join(" | ");
|
|
67801
|
+
return {
|
|
67802
|
+
kind: "oneOf",
|
|
67803
|
+
label,
|
|
67804
|
+
alternatives: alts,
|
|
67805
|
+
parse: (arg, ctx) => {
|
|
67806
|
+
for (const alt of alts) {
|
|
67807
|
+
const result = blindCast(alt.parse)(arg, ctx);
|
|
67808
|
+
if (result.ok) return ok$1(blindCast(result.value));
|
|
67809
|
+
}
|
|
67810
|
+
return notOk([leafDiagnostic(ctx, arg, `Expected one of: ${label}`)]);
|
|
67811
|
+
}
|
|
67812
|
+
};
|
|
67813
|
+
}
|
|
67814
|
+
function record(of) {
|
|
67815
|
+
return {
|
|
67816
|
+
kind: "record",
|
|
67817
|
+
label: `{ [key]: ${of.label} }`,
|
|
67818
|
+
of,
|
|
67819
|
+
parse: (arg, ctx) => {
|
|
67820
|
+
const literal = ObjectLiteralExprAst.cast(arg.syntax);
|
|
67821
|
+
if (literal === void 0) return notOk([leafDiagnostic(ctx, arg, "Expected an object literal")]);
|
|
67822
|
+
const diagnostics = [];
|
|
67823
|
+
const entries = [];
|
|
67824
|
+
const keys = /* @__PURE__ */ new Set();
|
|
67825
|
+
for (const field of Array.from(literal.fields())) {
|
|
67826
|
+
const key = field.keyName();
|
|
67827
|
+
if (key === void 0) {
|
|
67828
|
+
diagnostics.push(leafDiagnostic(ctx, field, "Expected a key"));
|
|
67829
|
+
continue;
|
|
67830
|
+
}
|
|
67831
|
+
const value = field.value();
|
|
67832
|
+
if (value === void 0) {
|
|
67833
|
+
diagnostics.push(leafDiagnostic(ctx, field, `Expected a value for key "${key}"`));
|
|
67834
|
+
continue;
|
|
67835
|
+
}
|
|
67836
|
+
const parsed = of.parse(value, ctx);
|
|
67837
|
+
if (!parsed.ok) {
|
|
67838
|
+
diagnostics.push(...parsed.failure);
|
|
67839
|
+
continue;
|
|
67840
|
+
}
|
|
67841
|
+
if (keys.has(key)) {
|
|
67842
|
+
diagnostics.push(leafDiagnostic(ctx, field, `Duplicate key "${key}"`));
|
|
67843
|
+
continue;
|
|
67844
|
+
}
|
|
67845
|
+
keys.add(key);
|
|
67846
|
+
entries.push([key, parsed.value]);
|
|
67847
|
+
}
|
|
67848
|
+
if (diagnostics.length > 0) return notOk(diagnostics);
|
|
67849
|
+
return ok$1(Object.fromEntries(entries));
|
|
67850
|
+
}
|
|
67851
|
+
};
|
|
67852
|
+
}
|
|
67853
|
+
function str(value) {
|
|
67854
|
+
if (value === void 0) return {
|
|
67855
|
+
kind: "str",
|
|
67856
|
+
label: "string",
|
|
67857
|
+
value: void 0,
|
|
67858
|
+
parse: (arg, ctx) => {
|
|
67859
|
+
const literal = StringLiteralExprAst.cast(arg.syntax);
|
|
67860
|
+
if (literal !== void 0) {
|
|
67861
|
+
const parsed = literal.value();
|
|
67862
|
+
if (parsed !== void 0) return ok$1(parsed);
|
|
67863
|
+
}
|
|
67864
|
+
return notOk([leafDiagnostic(ctx, arg, "Expected a string literal")]);
|
|
67865
|
+
}
|
|
67866
|
+
};
|
|
67867
|
+
return {
|
|
67868
|
+
kind: "str",
|
|
67869
|
+
label: JSON.stringify(value),
|
|
67870
|
+
value,
|
|
67871
|
+
parse: (arg, ctx) => {
|
|
67872
|
+
const literal = StringLiteralExprAst.cast(arg.syntax);
|
|
67873
|
+
if (literal !== void 0) {
|
|
67874
|
+
if (literal.value() === value) return ok$1(value);
|
|
67875
|
+
}
|
|
67876
|
+
return notOk([leafDiagnostic(ctx, arg, `Expected ${JSON.stringify(value)}`)]);
|
|
67877
|
+
}
|
|
67878
|
+
};
|
|
67879
|
+
}
|
|
67880
|
+
function fieldAttribute(name, config) {
|
|
67881
|
+
return {
|
|
67882
|
+
level: "field",
|
|
67883
|
+
name,
|
|
67884
|
+
positional: config.positional ?? [],
|
|
67885
|
+
named: config.named ?? {},
|
|
67886
|
+
...config.refine !== void 0 ? { refine: config.refine } : {}
|
|
67887
|
+
};
|
|
67888
|
+
}
|
|
67889
|
+
function modelAttribute(name, config) {
|
|
67890
|
+
return {
|
|
67891
|
+
level: "model",
|
|
67892
|
+
name,
|
|
67893
|
+
positional: config.positional ?? [],
|
|
67894
|
+
named: config.named ?? {},
|
|
67895
|
+
...config.refine !== void 0 ? { refine: config.refine } : {}
|
|
67896
|
+
};
|
|
67897
|
+
}
|
|
67898
|
+
function optional(type, ...rest) {
|
|
67899
|
+
if (rest.length === 0) return {
|
|
67900
|
+
...type,
|
|
67901
|
+
optional: true,
|
|
67902
|
+
hasDefault: false
|
|
67903
|
+
};
|
|
67904
|
+
return {
|
|
67905
|
+
...type,
|
|
67906
|
+
optional: true,
|
|
67907
|
+
hasDefault: true,
|
|
67908
|
+
defaultValue: rest[0]
|
|
67909
|
+
};
|
|
67910
|
+
}
|
|
67911
|
+
function findFieldAttributeNode(field, name) {
|
|
67912
|
+
for (const attribute of field.node.attributes()) if (attribute.name()?.isSimpleName(name) === true) return attribute;
|
|
67913
|
+
}
|
|
67914
|
+
const mapModelSpec = modelAttribute("map", { positional: [{
|
|
67915
|
+
key: "name",
|
|
67916
|
+
type: str()
|
|
67917
|
+
}] });
|
|
67918
|
+
const mapFieldSpec = fieldAttribute("map", { positional: [{
|
|
67919
|
+
key: "name",
|
|
67920
|
+
type: str()
|
|
67921
|
+
}] });
|
|
67922
|
+
function scalarDefaultArms(isList, registry) {
|
|
67923
|
+
const literal = () => oneOf(str(), num(), bool());
|
|
67924
|
+
const funcArms = [...registry.entries()].map(([name, entry]) => funcCall(name, blindCast(entry.signature)));
|
|
67925
|
+
return isList ? [list(literal()), ...funcArms] : [
|
|
67926
|
+
str(),
|
|
67927
|
+
num(),
|
|
67928
|
+
bool(),
|
|
67929
|
+
...funcArms
|
|
67930
|
+
];
|
|
67931
|
+
}
|
|
67932
|
+
function noEnumMember() {
|
|
67933
|
+
return {
|
|
67934
|
+
kind: "rejecting",
|
|
67935
|
+
label: "enum member",
|
|
67936
|
+
message: "Enum declares no members",
|
|
67937
|
+
parse: (arg, ctx) => notOk([leafDiagnostic(ctx, arg, "Enum declares no members")])
|
|
67938
|
+
};
|
|
67939
|
+
}
|
|
67940
|
+
function enumMemberNames(ctx) {
|
|
67941
|
+
const block = (ctx.field.typeNamespaceId === void 0 ? ctx.symbols.topLevel : ctx.symbols.topLevel.namespaces[ctx.field.typeNamespaceId])?.blocks[ctx.field.typeName];
|
|
67942
|
+
if (block === void 0 || block.keyword !== "enum") return void 0;
|
|
67943
|
+
return Object.keys(block.block.parameters);
|
|
67944
|
+
}
|
|
67945
|
+
function enumDefaultArms(members) {
|
|
67946
|
+
const [first, ...rest] = members;
|
|
67947
|
+
if (first === void 0) return [noEnumMember()];
|
|
67948
|
+
return [identifier(first), ...rest.map((name) => identifier(name))];
|
|
67949
|
+
}
|
|
67950
|
+
function defaultFieldSpec(ctx) {
|
|
67951
|
+
const members = enumMemberNames(ctx);
|
|
67952
|
+
return fieldAttribute("default", { positional: [{
|
|
67953
|
+
key: "value",
|
|
67954
|
+
type: oneOf(...members === void 0 ? scalarDefaultArms(ctx.field.list, ctx.controlMutationDefaults) : enumDefaultArms(members))
|
|
67955
|
+
}] });
|
|
67956
|
+
}
|
|
67957
|
+
const idFieldSpec = fieldAttribute("id", { named: { map: optional(str()) } });
|
|
67958
|
+
const uniqueFieldSpec = fieldAttribute("unique", { named: { map: optional(str()) } });
|
|
67959
|
+
const noCheckKindArgument = () => oneOf(identifier("membership"), identifier("elementNotNull"));
|
|
67960
|
+
/**
|
|
67961
|
+
* `@noCheck` waives generated CHECK constraints on one column: bare for every
|
|
67962
|
+
* kind the column's shape derives, or naming concrete kinds. Two optional
|
|
67963
|
+
* positional slots cover the whole kind vocabulary; a third argument is
|
|
67964
|
+
* necessarily a duplicate and fails as excess arity.
|
|
67965
|
+
*/
|
|
67966
|
+
const noCheckFieldSpec = fieldAttribute("noCheck", {
|
|
67967
|
+
positional: [{
|
|
67968
|
+
key: "first",
|
|
67969
|
+
type: optional(noCheckKindArgument())
|
|
67970
|
+
}, {
|
|
67971
|
+
key: "second",
|
|
67972
|
+
type: optional(noCheckKindArgument())
|
|
67973
|
+
}],
|
|
67974
|
+
refine: (value, ctx, attributeNode) => {
|
|
67975
|
+
if (value.first !== void 0 && value.first === value.second) return [leafDiagnostic(ctx, attributeNode, "`@noCheck` names the same kind twice")];
|
|
67976
|
+
return [];
|
|
67977
|
+
}
|
|
67978
|
+
});
|
|
67979
|
+
const idModelSpec = modelAttribute("id", {
|
|
67980
|
+
positional: [{
|
|
67981
|
+
key: "fields",
|
|
67982
|
+
type: list(fieldRef(), {
|
|
67983
|
+
allowEmpty: false,
|
|
67984
|
+
unique: true
|
|
67985
|
+
})
|
|
67986
|
+
}],
|
|
67987
|
+
named: { map: optional(str()) }
|
|
67988
|
+
});
|
|
67989
|
+
const uniqueModelSpec = modelAttribute("unique", {
|
|
67990
|
+
positional: [{
|
|
67991
|
+
key: "fields",
|
|
67992
|
+
type: list(fieldRef(), {
|
|
67993
|
+
allowEmpty: false,
|
|
67994
|
+
unique: true
|
|
67995
|
+
})
|
|
67996
|
+
}],
|
|
67997
|
+
named: { map: optional(str()) }
|
|
67998
|
+
});
|
|
67999
|
+
const PSL_INDEX_FIELDS_XOR_EXPRESSION = "PSL_INDEX_FIELDS_XOR_EXPRESSION";
|
|
68000
|
+
const PSL_INDEX_EXPRESSION_REQUIRES_NAME = "PSL_INDEX_EXPRESSION_REQUIRES_NAME";
|
|
68001
|
+
const PSL_INDEX_NAME_XOR_MAP = "PSL_INDEX_NAME_XOR_MAP";
|
|
68002
|
+
const indexModelSpec = modelAttribute("index", {
|
|
68003
|
+
positional: [{
|
|
68004
|
+
key: "fields",
|
|
68005
|
+
type: optional(list(fieldRef(), {
|
|
68006
|
+
allowEmpty: false,
|
|
68007
|
+
unique: true
|
|
68008
|
+
}))
|
|
68009
|
+
}],
|
|
68010
|
+
named: {
|
|
68011
|
+
expression: optional(str()),
|
|
68012
|
+
where: optional(str()),
|
|
68013
|
+
unique: optional(bool()),
|
|
68014
|
+
name: optional(str()),
|
|
68015
|
+
map: optional(str()),
|
|
68016
|
+
type: optional(str()),
|
|
68017
|
+
options: optional(record(str()))
|
|
68018
|
+
},
|
|
68019
|
+
refine: (value, ctx, attributeNode) => {
|
|
68020
|
+
const diagnostics = [];
|
|
68021
|
+
if (value.fields === void 0 === (value.expression === void 0)) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` requires exactly one of a fields list or an `expression` argument", PSL_INDEX_FIELDS_XOR_EXPRESSION));
|
|
68022
|
+
if (value.expression !== void 0 && value.name === void 0 && value.map === void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` with an `expression` argument requires a `name` or `map` argument (a default name cannot be derived from an expression)", PSL_INDEX_EXPRESSION_REQUIRES_NAME));
|
|
68023
|
+
if (value.name !== void 0 && value.map !== void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` takes at most one of `name` and `map`", PSL_INDEX_NAME_XOR_MAP));
|
|
68024
|
+
if (value.options !== void 0 && value.type === void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@index` options argument requires a type argument"));
|
|
68025
|
+
return diagnostics;
|
|
68026
|
+
}
|
|
68027
|
+
});
|
|
68028
|
+
const PSL_CHECK_REQUIRES_NAME_OR_MAP = "PSL_CHECK_REQUIRES_NAME_OR_MAP";
|
|
68029
|
+
const PSL_CHECK_NAME_XOR_MAP = "PSL_CHECK_NAME_XOR_MAP";
|
|
68030
|
+
const PSL_CHECK_EXPRESSION_EMPTY = "PSL_CHECK_EXPRESSION_EMPTY";
|
|
68031
|
+
const checkModelSpec = modelAttribute("check", {
|
|
68032
|
+
named: {
|
|
68033
|
+
expression: str(),
|
|
68034
|
+
name: optional(str()),
|
|
68035
|
+
map: optional(str())
|
|
68036
|
+
},
|
|
68037
|
+
refine: (value, ctx, attributeNode) => {
|
|
68038
|
+
const diagnostics = [];
|
|
68039
|
+
if (value.expression.trim().length === 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@check` expression must not be empty — an empty predicate is not a constraint", PSL_CHECK_EXPRESSION_EMPTY));
|
|
68040
|
+
if (value.name === void 0 && value.map === void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@check` requires a `name` or `map` argument (a default name cannot be derived — a check has no column tuple to name itself after)", PSL_CHECK_REQUIRES_NAME_OR_MAP));
|
|
68041
|
+
if (value.name !== void 0 && value.map !== void 0) diagnostics.push(leafDiagnostic(ctx, attributeNode, "`@@check` takes at most one of `name` and `map`", PSL_CHECK_NAME_XOR_MAP));
|
|
68042
|
+
return diagnostics;
|
|
68043
|
+
}
|
|
68044
|
+
});
|
|
68045
|
+
const controlModelSpec = modelAttribute("control", { positional: [{
|
|
68046
|
+
key: "policy",
|
|
68047
|
+
type: oneOf(identifier("managed"), identifier("tolerated"), identifier("external"), identifier("observed"))
|
|
68048
|
+
}] });
|
|
68049
|
+
const discriminatorModelSpec = modelAttribute("discriminator", { positional: [{
|
|
68050
|
+
key: "field",
|
|
68051
|
+
type: fieldRef()
|
|
68052
|
+
}] });
|
|
68053
|
+
const baseModelSpec = modelAttribute("base", { positional: [{
|
|
68054
|
+
key: "base",
|
|
68055
|
+
type: entityRef()
|
|
68056
|
+
}, {
|
|
68057
|
+
key: "value",
|
|
68058
|
+
type: str()
|
|
68059
|
+
}] });
|
|
68060
|
+
function relationAttributeSpan(ctx) {
|
|
68061
|
+
const node = findFieldAttributeNode(ctx.field, "relation");
|
|
68062
|
+
if (node !== void 0) return nodePslSpan(node.syntax, ctx.sourceFile);
|
|
68063
|
+
return ctx.field.span;
|
|
68064
|
+
}
|
|
68065
|
+
function relationInvariants(parsed, ctx) {
|
|
68066
|
+
if (parsed.fields !== void 0 !== (parsed.references !== void 0)) return [{
|
|
68067
|
+
code: "PSL_INVALID_ATTRIBUTE_SYNTAX",
|
|
68068
|
+
message: `Relation field "${ctx.selfModel.name}.${ctx.field.name}" requires fields and references arguments`,
|
|
68069
|
+
sourceId: ctx.sourceId,
|
|
68070
|
+
span: relationAttributeSpan(ctx)
|
|
68071
|
+
}];
|
|
68072
|
+
return [];
|
|
68073
|
+
}
|
|
68074
|
+
const referentialActionArgument = () => oneOf(identifier("NoAction"), identifier("Restrict"), identifier("Cascade"), identifier("SetNull"), identifier("SetDefault"));
|
|
68075
|
+
const relationFieldSpec = fieldAttribute("relation", {
|
|
68076
|
+
positional: [{
|
|
68077
|
+
key: "name",
|
|
68078
|
+
type: optional(str())
|
|
68079
|
+
}],
|
|
68080
|
+
named: {
|
|
68081
|
+
name: optional(str()),
|
|
68082
|
+
fields: optional(list(fieldRef(), {
|
|
68083
|
+
allowEmpty: false,
|
|
68084
|
+
unique: true
|
|
68085
|
+
})),
|
|
68086
|
+
references: optional(list(referencedFieldRef(), {
|
|
68087
|
+
allowEmpty: false,
|
|
68088
|
+
unique: true
|
|
68089
|
+
})),
|
|
68090
|
+
map: optional(str()),
|
|
68091
|
+
onDelete: optional(referentialActionArgument()),
|
|
68092
|
+
onUpdate: optional(referentialActionArgument()),
|
|
68093
|
+
index: optional(bool())
|
|
68094
|
+
},
|
|
68095
|
+
refine: relationInvariants
|
|
68096
|
+
});
|
|
68097
|
+
const sqlAttributeSpecs = {
|
|
68098
|
+
model: {
|
|
68099
|
+
map: () => mapModelSpec,
|
|
68100
|
+
id: () => idModelSpec,
|
|
68101
|
+
unique: () => uniqueModelSpec,
|
|
68102
|
+
index: () => indexModelSpec,
|
|
68103
|
+
check: () => checkModelSpec,
|
|
68104
|
+
control: () => controlModelSpec,
|
|
68105
|
+
discriminator: () => discriminatorModelSpec,
|
|
68106
|
+
base: () => baseModelSpec
|
|
68107
|
+
},
|
|
68108
|
+
field: {
|
|
68109
|
+
map: () => mapFieldSpec,
|
|
68110
|
+
id: () => idFieldSpec,
|
|
68111
|
+
unique: () => uniqueFieldSpec,
|
|
68112
|
+
noCheck: () => noCheckFieldSpec,
|
|
68113
|
+
relation: () => relationFieldSpec,
|
|
68114
|
+
default: defaultFieldSpec
|
|
68115
|
+
}
|
|
68116
|
+
};
|
|
66512
68117
|
function isSafeTypeExpression(expr) {
|
|
66513
68118
|
return !/import\s*\(|require\s*\(|declare\s|export\s|eval\s*\(/.test(expr);
|
|
66514
68119
|
}
|
|
@@ -66595,6 +68200,7 @@ function generateModelRelationsType(relations) {
|
|
|
66595
68200
|
const parts = [];
|
|
66596
68201
|
if (toRef) parts.push(`readonly to: ${serializeCrossReference(blindCast(toRef))}`);
|
|
66597
68202
|
if (relObj["cardinality"]) parts.push(`readonly cardinality: ${serializeValue(relObj["cardinality"])}`);
|
|
68203
|
+
if (typeof relObj["nullable"] === "boolean") parts.push(`readonly nullable: ${relObj["nullable"]}`);
|
|
66598
68204
|
const on = relObj["on"];
|
|
66599
68205
|
if (on && (!on.localFields || !on.targetFields)) throw emitterError("CONTRACT.RELATION_INVALID", `Relation "${relName}" has an "on" block but is missing localFields or targetFields`, { meta: { relation: relName } });
|
|
66600
68206
|
if (on?.localFields && on.targetFields) {
|
|
@@ -66748,11 +68354,26 @@ function resolveFieldType(field, codecLookup, resolvedTypeParams, resolvedValueS
|
|
|
66748
68354
|
};
|
|
66749
68355
|
}
|
|
66750
68356
|
}
|
|
68357
|
+
/**
|
|
68358
|
+
* Resolves one model field's input and output types the way `FieldOutputTypes` /
|
|
68359
|
+
* `FieldInputTypes` do: inline type params win over the family resolver, and a family-resolved
|
|
68360
|
+
* value set renders as a literal union.
|
|
68361
|
+
*/
|
|
68362
|
+
function resolveModelFieldType(modelName, fieldName, field, model, resolvers) {
|
|
68363
|
+
const resolvedTypeParams = (field.type.kind === "scalar" && field.type.typeParams && Object.keys(field.type.typeParams).length > 0 ? field.type.typeParams : void 0) ?? resolvers.resolveFieldTypeParams?.(modelName, fieldName, model);
|
|
68364
|
+
const resolvedValueSet = resolvers.resolveFieldValueSet?.(modelName, fieldName, model);
|
|
68365
|
+
return resolveFieldType(field, resolvers.codecLookup, resolvedTypeParams, resolvedValueSet);
|
|
68366
|
+
}
|
|
66751
68367
|
function generateBothFieldTypesMaps(models, codecLookup, resolveFieldTypeParams, resolveFieldValueSet) {
|
|
66752
68368
|
if (!models || Object.keys(models).length === 0) return {
|
|
66753
68369
|
output: "Record<string, never>",
|
|
66754
68370
|
input: "Record<string, never>"
|
|
66755
68371
|
};
|
|
68372
|
+
const resolvers = {
|
|
68373
|
+
codecLookup,
|
|
68374
|
+
resolveFieldTypeParams,
|
|
68375
|
+
resolveFieldValueSet
|
|
68376
|
+
};
|
|
66756
68377
|
const outputModelEntries = [];
|
|
66757
68378
|
const inputModelEntries = [];
|
|
66758
68379
|
for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {
|
|
@@ -66760,9 +68381,7 @@ function generateBothFieldTypesMaps(models, codecLookup, resolveFieldTypeParams,
|
|
|
66760
68381
|
const outputFieldEntries = [];
|
|
66761
68382
|
const inputFieldEntries = [];
|
|
66762
68383
|
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
66763
|
-
const
|
|
66764
|
-
const resolvedValueSet = resolveFieldValueSet?.(modelName, fieldName, model);
|
|
66765
|
-
const resolved = resolveFieldType(field, codecLookup, resolvedTypeParams, resolvedValueSet);
|
|
68384
|
+
const resolved = resolveModelFieldType(modelName, fieldName, field, model, resolvers);
|
|
66766
68385
|
const key = `readonly ${serializeObjectKey(fieldName)}`;
|
|
66767
68386
|
outputFieldEntries.push(`${key}: ${resolved.output}`);
|
|
66768
68387
|
inputFieldEntries.push(`${key}: ${resolved.input}`);
|
|
@@ -67197,6 +68816,7 @@ const sqlEmission = {
|
|
|
67197
68816
|
return [
|
|
67198
68817
|
"import type {",
|
|
67199
68818
|
" ContractWithTypeMaps,",
|
|
68819
|
+
" RelationKeys,",
|
|
67200
68820
|
" TypeMaps as TypeMapsType,",
|
|
67201
68821
|
`} from '${resolveImportSpecifier("@internal/sql-contract/types")}';`
|
|
67202
68822
|
];
|
|
@@ -67390,9 +69010,9 @@ const EXACT_NAME_BODY_PREAMBLE = "Drift detection compares the authored SQL text
|
|
|
67390
69010
|
* block's head the wire prefix.
|
|
67391
69011
|
*/
|
|
67392
69012
|
const EXACT_NAME_BODY_REMEDIATION = {
|
|
67393
|
-
index: "For hand-authored definitions, use name: and let Prisma
|
|
69013
|
+
index: "For hand-authored definitions, use name: and let Prisma 8 manage the physical name; to migrate an adopted object to wire naming, replace map: with name: (keeping the body text unchanged) and apply the resulting rename migration.",
|
|
67394
69014
|
policy: "For hand-authored definitions, drop @@map and let the policy block's head name the policy; to migrate an adopted policy to wire naming, remove @@map (keeping the body text unchanged) and apply the resulting rename migration.",
|
|
67395
|
-
check: "For hand-authored definitions, use name: and let Prisma
|
|
69015
|
+
check: "For hand-authored definitions, use name: and let Prisma 8 manage the physical name; to migrate an adopted check to wire naming, replace map: with name: (keeping the body text unchanged) and apply the resulting rename migration."
|
|
67396
69016
|
};
|
|
67397
69017
|
/** What the user actually wrote, per subject: index and check `map:`, policy `@@map`. */
|
|
67398
69018
|
const EXACT_NAME_FEATURE = {
|
|
@@ -67493,6 +69113,7 @@ function validateContractDomain(contract) {
|
|
|
67493
69113
|
validateRoots(contract, modelIndex, errors);
|
|
67494
69114
|
validateVariantsAndBases(modelIndex, errors);
|
|
67495
69115
|
validateRelationTargets(modelIndex, errors);
|
|
69116
|
+
validateRelationNullability(modelIndex, errors);
|
|
67496
69117
|
validateDiscriminators(modelIndex, errors);
|
|
67497
69118
|
validateOwnership(contract, modelIndex, errors);
|
|
67498
69119
|
validateValueObjectReferences(contract, errors);
|
|
@@ -67542,6 +69163,19 @@ function validateRelationTargets(modelIndex, errors) {
|
|
|
67542
69163
|
if (!lookupModel(modelIndex, relation.to)) errors.push(`Relation "${relName}" on model "${namespaceId}:${modelName}" targets "${relation.to.namespace}:${relation.to.model}" which does not exist in domain.namespaces`);
|
|
67543
69164
|
}
|
|
67544
69165
|
}
|
|
69166
|
+
function relationKindLabel(relation) {
|
|
69167
|
+
return relation.on === void 0 ? "embed relation" : `${relation.cardinality} relation`;
|
|
69168
|
+
}
|
|
69169
|
+
function validateRelationNullability(modelIndex, errors) {
|
|
69170
|
+
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) for (const [relName, relation] of Object.entries(model.relations ?? {})) {
|
|
69171
|
+
const location = `Relation "${relName}" on model "${namespaceId}:${modelName}"`;
|
|
69172
|
+
if (relation.on !== void 0 && (relation.cardinality === "1:1" || relation.cardinality === "N:1")) {
|
|
69173
|
+
if (relation.nullable !== void 0 && typeof relation.nullable !== "boolean") errors.push(`${location} is a ${relation.cardinality} relation and its "nullable" must be a boolean`);
|
|
69174
|
+
continue;
|
|
69175
|
+
}
|
|
69176
|
+
if (relation.nullable !== void 0) errors.push(`${location} is a ${relationKindLabel(relation)} and must not carry "nullable"`);
|
|
69177
|
+
}
|
|
69178
|
+
}
|
|
67545
69179
|
function validateDiscriminators(modelIndex, errors) {
|
|
67546
69180
|
for (const { namespaceId, name: modelName, model } of iterateIndexedModels(modelIndex)) {
|
|
67547
69181
|
if (model.discriminator) {
|
|
@@ -67600,6 +69234,29 @@ function validateFieldModifiers(modelIndex, contract, errors) {
|
|
|
67600
69234
|
}
|
|
67601
69235
|
}
|
|
67602
69236
|
}
|
|
69237
|
+
function sameColumns(left, right) {
|
|
69238
|
+
return left.length === right.length && left.every((column, index) => column === right[index]);
|
|
69239
|
+
}
|
|
69240
|
+
/**
|
|
69241
|
+
* The storage facts behind a same-space to-one relation's nullability: which side owns the
|
|
69242
|
+
* foreign key, and whether each local column is nullable.
|
|
69243
|
+
*/
|
|
69244
|
+
function resolveSqlToOneRelationStorage(contract, modelStorage, relation) {
|
|
69245
|
+
const table = blindCast(contract.storage.namespaces[modelStorage.namespaceId]?.entries.table?.[modelStorage.table]);
|
|
69246
|
+
const columns = relation.on.localFields.map((fieldName) => {
|
|
69247
|
+
const columnName = modelStorage.fields[fieldName]?.column;
|
|
69248
|
+
const column = columnName === void 0 ? void 0 : table?.columns[columnName];
|
|
69249
|
+
return {
|
|
69250
|
+
name: columnName ?? fieldName,
|
|
69251
|
+
nullable: column?.nullable ?? true
|
|
69252
|
+
};
|
|
69253
|
+
});
|
|
69254
|
+
const columnNames = columns.map((column) => column.name);
|
|
69255
|
+
return {
|
|
69256
|
+
ownsForeignKey: relation.cardinality === "N:1" || (table?.foreignKeys ?? []).some((foreignKey) => sameColumns(foreignKey.source.columns, columnNames)),
|
|
69257
|
+
columns
|
|
69258
|
+
};
|
|
69259
|
+
}
|
|
67603
69260
|
const generatorKindSchema = type("'generator'");
|
|
67604
69261
|
const ControlPolicySchema = type("'managed' | 'tolerated' | 'external' | 'observed'");
|
|
67605
69262
|
const ExecutionMutationDefaultValueSchema = type({
|
|
@@ -67849,13 +69506,20 @@ const ContractManyToManyRelationSchema = type({
|
|
|
67849
69506
|
on: ContractRelationOnSchema,
|
|
67850
69507
|
through: ContractRelationThroughSchema
|
|
67851
69508
|
});
|
|
67852
|
-
const
|
|
69509
|
+
const ContractToOneRelationSchema = type({
|
|
69510
|
+
"+": "reject",
|
|
69511
|
+
to: CrossReferenceSchema,
|
|
69512
|
+
cardinality: "'1:1' | 'N:1'",
|
|
69513
|
+
"nullable?": "boolean",
|
|
69514
|
+
on: ContractRelationOnSchema
|
|
69515
|
+
});
|
|
69516
|
+
const ContractToManyRelationSchema = type({
|
|
67853
69517
|
"+": "reject",
|
|
67854
69518
|
to: CrossReferenceSchema,
|
|
67855
|
-
cardinality: "'1:
|
|
69519
|
+
cardinality: "'1:N'",
|
|
67856
69520
|
on: ContractRelationOnSchema
|
|
67857
69521
|
});
|
|
67858
|
-
const ContractReferenceRelationSchema = ContractManyToManyRelationSchema.or(
|
|
69522
|
+
const ContractReferenceRelationSchema = ContractManyToManyRelationSchema.or(ContractToOneRelationSchema).or(ContractToManyRelationSchema);
|
|
67859
69523
|
const ContractEmbedRelationSchema = type({
|
|
67860
69524
|
"+": "reject",
|
|
67861
69525
|
to: CrossReferenceSchema,
|
|
@@ -68070,8 +69734,32 @@ function validateSqlContractFully(value, options) {
|
|
|
68070
69734
|
if (semanticErrors.length > 0) throw new ContractValidationError(`Contract semantic validation failed: ${semanticErrors.join("; ")}`, "storage");
|
|
68071
69735
|
validateModelStorageReferences(validated);
|
|
68072
69736
|
validateRelationThroughConsistency(validated);
|
|
69737
|
+
validateToOneRelationNullabilityAgainstStorage(validated);
|
|
68073
69738
|
return validated;
|
|
68074
69739
|
}
|
|
69740
|
+
/**
|
|
69741
|
+
* A same-space to-one relation that states `nullable` must agree with its local FK columns:
|
|
69742
|
+
* nullable exactly when one of them is nullable (a column that cannot be resolved counts as
|
|
69743
|
+
* nullable). A relation without the flag is left to hydration, which derives it the same way.
|
|
69744
|
+
*/
|
|
69745
|
+
function validateToOneRelationNullabilityAgainstStorage(contract) {
|
|
69746
|
+
for (const [namespaceId, namespace] of Object.entries(contract.domain.namespaces)) for (const [modelName, model] of Object.entries(namespace.models)) {
|
|
69747
|
+
const storage = blindCast(model.storage);
|
|
69748
|
+
for (const [relationName, relation] of Object.entries(model.relations)) {
|
|
69749
|
+
if (!("on" in relation && (relation.cardinality === "1:1" || relation.cardinality === "N:1") && relation.to.space === void 0) || relation.nullable === void 0) continue;
|
|
69750
|
+
const location = `Relation "${relationName}" on model "${namespaceId}:${modelName}"`;
|
|
69751
|
+
const { ownsForeignKey, columns } = resolveSqlToOneRelationStorage(contract, storage, relation);
|
|
69752
|
+
if (!ownsForeignKey) {
|
|
69753
|
+
if (relation.nullable) continue;
|
|
69754
|
+
throw new ContractValidationError(`${location} is required but does not own the foreign key, so nothing in storage guarantees the related row exists`, "storage");
|
|
69755
|
+
}
|
|
69756
|
+
const anyNullable = columns.some((column) => column.nullable);
|
|
69757
|
+
if (relation.nullable === anyNullable) continue;
|
|
69758
|
+
const columnList = columns.filter((column) => column.nullable !== relation.nullable).map((column) => `"${column.name}"`).join(", ");
|
|
69759
|
+
throw new ContractValidationError(relation.nullable ? `${location} is nullable but every local FK column is NOT NULL (columns ${columnList})` : `${location} is required but a local FK column is nullable (columns ${columnList})`, "storage");
|
|
69760
|
+
}
|
|
69761
|
+
}
|
|
69762
|
+
}
|
|
68075
69763
|
/** Storage column lookup for through-consistency validation. */
|
|
68076
69764
|
function lookupStorageColumn(contract, namespaceId, tableName, columnName) {
|
|
68077
69765
|
const rawTable = contract.storage.namespaces[namespaceId]?.entries.table?.[tableName];
|
|
@@ -68173,188 +69861,6 @@ function validateRelationThroughConsistency(contract) {
|
|
|
68173
69861
|
});
|
|
68174
69862
|
}
|
|
68175
69863
|
}
|
|
68176
|
-
const DOMAIN_NAMESPACE_SLOT_PATTERN = [
|
|
68177
|
-
"domain",
|
|
68178
|
-
"namespaces",
|
|
68179
|
-
"*"
|
|
68180
|
-
];
|
|
68181
|
-
const DOMAIN_MODELS_CONTAINER_PATTERN = [
|
|
68182
|
-
"domain",
|
|
68183
|
-
"namespaces",
|
|
68184
|
-
"*",
|
|
68185
|
-
"models"
|
|
68186
|
-
];
|
|
68187
|
-
const DOMAIN_MODEL_RELATIONS_PATTERN = [
|
|
68188
|
-
"domain",
|
|
68189
|
-
"namespaces",
|
|
68190
|
-
"*",
|
|
68191
|
-
"models",
|
|
68192
|
-
"*",
|
|
68193
|
-
"relations"
|
|
68194
|
-
];
|
|
68195
|
-
const DOMAIN_MODEL_STORAGE_PATTERN = [
|
|
68196
|
-
"domain",
|
|
68197
|
-
"namespaces",
|
|
68198
|
-
"*",
|
|
68199
|
-
"models",
|
|
68200
|
-
"*",
|
|
68201
|
-
"storage"
|
|
68202
|
-
];
|
|
68203
|
-
const STORAGE_NAMESPACE_ENTRIES_PATTERN = [
|
|
68204
|
-
"storage",
|
|
68205
|
-
"namespaces",
|
|
68206
|
-
"*",
|
|
68207
|
-
"entries"
|
|
68208
|
-
];
|
|
68209
|
-
const TOP_LEVEL_ORDER = [
|
|
68210
|
-
"schemaVersion",
|
|
68211
|
-
"canonicalVersion",
|
|
68212
|
-
"targetFamily",
|
|
68213
|
-
"target",
|
|
68214
|
-
"profileHash",
|
|
68215
|
-
"roots",
|
|
68216
|
-
"domain",
|
|
68217
|
-
"storage",
|
|
68218
|
-
"execution",
|
|
68219
|
-
"capabilities",
|
|
68220
|
-
"extensions",
|
|
68221
|
-
"defaultControlPolicy",
|
|
68222
|
-
"meta"
|
|
68223
|
-
];
|
|
68224
|
-
function isDefaultValue(value) {
|
|
68225
|
-
if (value === false) return true;
|
|
68226
|
-
if (value === null) return false;
|
|
68227
|
-
if (Array.isArray(value) && value.length === 0) return true;
|
|
68228
|
-
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
68229
|
-
return false;
|
|
68230
|
-
}
|
|
68231
|
-
function omitDefaults(obj, path, shouldPreserveEmpty) {
|
|
68232
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
68233
|
-
if (Array.isArray(obj)) return obj.map((item) => omitDefaults(item, path, shouldPreserveEmpty));
|
|
68234
|
-
const result = {};
|
|
68235
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
68236
|
-
const currentPath = [...path, key];
|
|
68237
|
-
if (key === "_generated") continue;
|
|
68238
|
-
if (key === "generated" && value === false) continue;
|
|
68239
|
-
if ((key === "onDelete" || key === "onUpdate") && value === "noAction") continue;
|
|
68240
|
-
if (isDefaultValue(value)) {
|
|
68241
|
-
const isRequiredDomainNamespaces = isArrayEqual(currentPath, ["domain", "namespaces"]);
|
|
68242
|
-
const isDomainNamespaceSlot = matchesPathPattern(currentPath, DOMAIN_NAMESPACE_SLOT_PATTERN);
|
|
68243
|
-
const isRequiredDomainModels = matchesPathPattern(currentPath, DOMAIN_MODELS_CONTAINER_PATTERN);
|
|
68244
|
-
const isRequiredStorageNamespaces = isArrayEqual(currentPath, ["storage", "namespaces"]);
|
|
68245
|
-
const isStorageNamespaceEntries = matchesPathPattern(currentPath, STORAGE_NAMESPACE_ENTRIES_PATTERN);
|
|
68246
|
-
const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
|
|
68247
|
-
const isRequiredExtensions = isArrayEqual(currentPath, ["extensions"]);
|
|
68248
|
-
const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
|
|
68249
|
-
const isRequiredMeta = isArrayEqual(currentPath, ["meta"]);
|
|
68250
|
-
const isRequiredExecutionDefaults = isArrayEqual(currentPath, [
|
|
68251
|
-
"execution",
|
|
68252
|
-
"mutations",
|
|
68253
|
-
"defaults"
|
|
68254
|
-
]);
|
|
68255
|
-
const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === "extensions";
|
|
68256
|
-
const isModelRelations = matchesPathPattern(currentPath, DOMAIN_MODEL_RELATIONS_PATTERN);
|
|
68257
|
-
const isModelStorage = matchesPathPattern(currentPath, DOMAIN_MODEL_STORAGE_PATTERN);
|
|
68258
|
-
const isNullableField = key === "nullable";
|
|
68259
|
-
const isFamilyPreserved = shouldPreserveEmpty?.(currentPath) ?? false;
|
|
68260
|
-
if (!isRequiredDomainNamespaces && !isDomainNamespaceSlot && !isRequiredDomainModels && !isRequiredStorageNamespaces && !isStorageNamespaceEntries && !isRequiredRoots && !isRequiredExtensions && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isModelStorage && !isNullableField && !isFamilyPreserved) continue;
|
|
68261
|
-
}
|
|
68262
|
-
result[key] = omitDefaults(value, currentPath, shouldPreserveEmpty);
|
|
68263
|
-
}
|
|
68264
|
-
return result;
|
|
68265
|
-
}
|
|
68266
|
-
function sortObjectKeys(obj) {
|
|
68267
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
68268
|
-
if (Array.isArray(obj)) return obj.map((item) => sortObjectKeys(item));
|
|
68269
|
-
const sorted = {};
|
|
68270
|
-
const keys = Object.keys(obj).sort();
|
|
68271
|
-
for (const key of keys) sorted[key] = sortObjectKeys(obj[key]);
|
|
68272
|
-
return sorted;
|
|
68273
|
-
}
|
|
68274
|
-
function orderTopLevel(obj) {
|
|
68275
|
-
const ordered = {};
|
|
68276
|
-
const remaining = new Set(Object.keys(obj));
|
|
68277
|
-
for (const key of TOP_LEVEL_ORDER) if (remaining.has(key)) {
|
|
68278
|
-
ordered[key] = obj[key];
|
|
68279
|
-
remaining.delete(key);
|
|
68280
|
-
}
|
|
68281
|
-
for (const key of Array.from(remaining).sort()) ordered[key] = obj[key];
|
|
68282
|
-
return ordered;
|
|
68283
|
-
}
|
|
68284
|
-
/**
|
|
68285
|
-
* Object-form variant of {@link canonicalizeContract}. Exported because the
|
|
68286
|
-
* emitter writes the canonical contract through a separate JSON-stringify
|
|
68287
|
-
* pass and consumes the structured object directly.
|
|
68288
|
-
*/
|
|
68289
|
-
function canonicalizeContractToObject(contract, options) {
|
|
68290
|
-
const serialized = options.serializeContract(contract);
|
|
68291
|
-
const withDefaultsOmitted = omitDefaults({
|
|
68292
|
-
...ifDefined("schemaVersion", options.schemaVersion),
|
|
68293
|
-
targetFamily: serialized["targetFamily"],
|
|
68294
|
-
target: serialized["target"],
|
|
68295
|
-
profileHash: serialized["profileHash"],
|
|
68296
|
-
roots: serialized["roots"],
|
|
68297
|
-
domain: serialized["domain"],
|
|
68298
|
-
storage: serialized["storage"],
|
|
68299
|
-
...ifDefined("execution", serialized["execution"]),
|
|
68300
|
-
extensions: serialized["extensions"],
|
|
68301
|
-
capabilities: serialized["capabilities"],
|
|
68302
|
-
...ifDefined("defaultControlPolicy", serialized["defaultControlPolicy"]),
|
|
68303
|
-
meta: serialized["meta"]
|
|
68304
|
-
}, [], options.shouldPreserveEmpty);
|
|
68305
|
-
return orderTopLevel(sortObjectKeys(options.sortStorage ? {
|
|
68306
|
-
...withDefaultsOmitted,
|
|
68307
|
-
storage: options.sortStorage(withDefaultsOmitted["storage"])
|
|
68308
|
-
} : withDefaultsOmitted));
|
|
68309
|
-
}
|
|
68310
|
-
function canonicalizeContract(contract, options) {
|
|
68311
|
-
return JSON.stringify(canonicalizeContractToObject(contract, options), null, 2);
|
|
68312
|
-
}
|
|
68313
|
-
const SCHEMA_VERSION$1 = "1";
|
|
68314
|
-
function omitNamespaceKindsForHash(storage) {
|
|
68315
|
-
if (!isPlainRecord(storage)) return storage;
|
|
68316
|
-
const namespaces = storage["namespaces"];
|
|
68317
|
-
if (!isPlainRecord(namespaces)) return storage;
|
|
68318
|
-
const stripped = {};
|
|
68319
|
-
for (const [nsId, ns] of Object.entries(namespaces)) if (isPlainRecord(ns)) {
|
|
68320
|
-
const { kind: _kind, ...rest } = ns;
|
|
68321
|
-
stripped[nsId] = rest;
|
|
68322
|
-
} else stripped[nsId] = ns;
|
|
68323
|
-
return {
|
|
68324
|
-
...storage,
|
|
68325
|
-
namespaces: stripped
|
|
68326
|
-
};
|
|
68327
|
-
}
|
|
68328
|
-
function sha256(content) {
|
|
68329
|
-
const hash = createHash("sha256");
|
|
68330
|
-
hash.update(content);
|
|
68331
|
-
return hash.digest("hex");
|
|
68332
|
-
}
|
|
68333
|
-
function hashContract(section) {
|
|
68334
|
-
const { shouldPreserveEmpty, sortStorage, ...sectionData } = section;
|
|
68335
|
-
const storageForHash = omitNamespaceKindsForHash(sectionData["storage"] ?? {});
|
|
68336
|
-
return canonicalizeContract(blindCast({
|
|
68337
|
-
targetFamily: sectionData["targetFamily"],
|
|
68338
|
-
target: sectionData["target"],
|
|
68339
|
-
roots: {},
|
|
68340
|
-
domain: { namespaces: {} },
|
|
68341
|
-
execution: sectionData["execution"],
|
|
68342
|
-
extensions: {},
|
|
68343
|
-
capabilities: sectionData["capabilities"] ?? {},
|
|
68344
|
-
meta: {},
|
|
68345
|
-
profileHash: "",
|
|
68346
|
-
...sectionData,
|
|
68347
|
-
storage: storageForHash
|
|
68348
|
-
}), {
|
|
68349
|
-
schemaVersion: SCHEMA_VERSION$1,
|
|
68350
|
-
serializeContract: (c) => castAs(JSON.parse(JSON.stringify(c))),
|
|
68351
|
-
...ifDefined("shouldPreserveEmpty", shouldPreserveEmpty),
|
|
68352
|
-
...ifDefined("sortStorage", sortStorage)
|
|
68353
|
-
});
|
|
68354
|
-
}
|
|
68355
|
-
function computeStorageHash(args) {
|
|
68356
|
-
return blindCast(sha256(hashContract(args)));
|
|
68357
|
-
}
|
|
68358
69864
|
function contractError$1(code, message, options) {
|
|
68359
69865
|
return structuredError(code, message, options);
|
|
68360
69866
|
}
|
|
@@ -68405,6 +69911,251 @@ function enumType(name, codec, ...members) {
|
|
|
68405
69911
|
ordinalOf: (v) => valueToOrdinal.get(v) ?? -1
|
|
68406
69912
|
};
|
|
68407
69913
|
}
|
|
69914
|
+
/**
|
|
69915
|
+
* The one rule for whether a to-one relation may be absent. The side that holds the reference
|
|
69916
|
+
* (in SQL, the foreign key) is nullable exactly when one of its local fields is; the other side
|
|
69917
|
+
* is always nullable, because nothing in storage guarantees the related record exists. A
|
|
69918
|
+
* declaration that disagrees is reported as a contradiction; `nullable` is always the derived
|
|
69919
|
+
* value.
|
|
69920
|
+
*/
|
|
69921
|
+
function resolveToOneRelationNullable(input) {
|
|
69922
|
+
const nullable = input.ownsReference ? input.localFieldNullability.some(Boolean) : true;
|
|
69923
|
+
const declared = input.declaredNullable;
|
|
69924
|
+
if (declared === void 0 || declared === nullable) return {
|
|
69925
|
+
nullable,
|
|
69926
|
+
contradiction: void 0
|
|
69927
|
+
};
|
|
69928
|
+
return {
|
|
69929
|
+
nullable,
|
|
69930
|
+
contradiction: declared ? "declared-optional" : "declared-required"
|
|
69931
|
+
};
|
|
69932
|
+
}
|
|
69933
|
+
function isToOneReference(relation) {
|
|
69934
|
+
return "on" in relation && (relation.cardinality === "1:1" || relation.cardinality === "N:1");
|
|
69935
|
+
}
|
|
69936
|
+
/**
|
|
69937
|
+
* Fills in `nullable` on every same-space to-one relation that lacks it from the ownership and
|
|
69938
|
+
* local-field nullability the lookup reports. A cross-space relation defaults to nullable.
|
|
69939
|
+
* Relations that already carry the flag are left as they are.
|
|
69940
|
+
*/
|
|
69941
|
+
function withDerivedToOneRelationNullability(domain, localFieldNullability) {
|
|
69942
|
+
const namespaces = Object.fromEntries(Object.entries(domain.namespaces).map(([namespaceId, namespace]) => [namespaceId, withDerivedNamespace(namespaceId, namespace, localFieldNullability)]));
|
|
69943
|
+
return {
|
|
69944
|
+
...domain,
|
|
69945
|
+
namespaces
|
|
69946
|
+
};
|
|
69947
|
+
}
|
|
69948
|
+
function withDerivedNamespace(namespaceId, namespace, localFieldNullability) {
|
|
69949
|
+
const models = Object.fromEntries(Object.entries(namespace.models).map(([modelName, model]) => [modelName, withDerivedModel(namespaceId, modelName, model, localFieldNullability)]));
|
|
69950
|
+
return {
|
|
69951
|
+
...namespace,
|
|
69952
|
+
models
|
|
69953
|
+
};
|
|
69954
|
+
}
|
|
69955
|
+
function withDerivedModel(namespaceId, modelName, model, localFieldNullability) {
|
|
69956
|
+
const relations = Object.fromEntries(Object.entries(model.relations ?? {}).map(([relationName, relation]) => {
|
|
69957
|
+
if (!isToOneReference(relation) || relation.nullable !== void 0) return [relationName, relation];
|
|
69958
|
+
const nullable = relation.to.space !== void 0 ? true : resolveToOneRelationNullable({
|
|
69959
|
+
declaredNullable: void 0,
|
|
69960
|
+
...localFieldNullability({
|
|
69961
|
+
namespaceId,
|
|
69962
|
+
modelName,
|
|
69963
|
+
model,
|
|
69964
|
+
relation
|
|
69965
|
+
})
|
|
69966
|
+
}).nullable;
|
|
69967
|
+
return [relationName, {
|
|
69968
|
+
...relation,
|
|
69969
|
+
nullable
|
|
69970
|
+
}];
|
|
69971
|
+
}));
|
|
69972
|
+
return {
|
|
69973
|
+
...model,
|
|
69974
|
+
relations
|
|
69975
|
+
};
|
|
69976
|
+
}
|
|
69977
|
+
const DOMAIN_NAMESPACE_SLOT_PATTERN = [
|
|
69978
|
+
"domain",
|
|
69979
|
+
"namespaces",
|
|
69980
|
+
"*"
|
|
69981
|
+
];
|
|
69982
|
+
const DOMAIN_MODELS_CONTAINER_PATTERN = [
|
|
69983
|
+
"domain",
|
|
69984
|
+
"namespaces",
|
|
69985
|
+
"*",
|
|
69986
|
+
"models"
|
|
69987
|
+
];
|
|
69988
|
+
const DOMAIN_MODEL_RELATIONS_PATTERN = [
|
|
69989
|
+
"domain",
|
|
69990
|
+
"namespaces",
|
|
69991
|
+
"*",
|
|
69992
|
+
"models",
|
|
69993
|
+
"*",
|
|
69994
|
+
"relations"
|
|
69995
|
+
];
|
|
69996
|
+
const DOMAIN_MODEL_STORAGE_PATTERN = [
|
|
69997
|
+
"domain",
|
|
69998
|
+
"namespaces",
|
|
69999
|
+
"*",
|
|
70000
|
+
"models",
|
|
70001
|
+
"*",
|
|
70002
|
+
"storage"
|
|
70003
|
+
];
|
|
70004
|
+
const STORAGE_NAMESPACE_ENTRIES_PATTERN = [
|
|
70005
|
+
"storage",
|
|
70006
|
+
"namespaces",
|
|
70007
|
+
"*",
|
|
70008
|
+
"entries"
|
|
70009
|
+
];
|
|
70010
|
+
const TOP_LEVEL_ORDER = [
|
|
70011
|
+
"schemaVersion",
|
|
70012
|
+
"canonicalVersion",
|
|
70013
|
+
"targetFamily",
|
|
70014
|
+
"target",
|
|
70015
|
+
"profileHash",
|
|
70016
|
+
"roots",
|
|
70017
|
+
"domain",
|
|
70018
|
+
"storage",
|
|
70019
|
+
"execution",
|
|
70020
|
+
"capabilities",
|
|
70021
|
+
"extensions",
|
|
70022
|
+
"defaultControlPolicy",
|
|
70023
|
+
"meta"
|
|
70024
|
+
];
|
|
70025
|
+
function isDefaultValue(value) {
|
|
70026
|
+
if (value === false) return true;
|
|
70027
|
+
if (value === null) return false;
|
|
70028
|
+
if (Array.isArray(value) && value.length === 0) return true;
|
|
70029
|
+
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
70030
|
+
return false;
|
|
70031
|
+
}
|
|
70032
|
+
function omitDefaults(obj, path, shouldPreserveEmpty) {
|
|
70033
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
70034
|
+
if (Array.isArray(obj)) return obj.map((item) => omitDefaults(item, path, shouldPreserveEmpty));
|
|
70035
|
+
const result = {};
|
|
70036
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
70037
|
+
const currentPath = [...path, key];
|
|
70038
|
+
if (key === "_generated") continue;
|
|
70039
|
+
if (key === "generated" && value === false) continue;
|
|
70040
|
+
if ((key === "onDelete" || key === "onUpdate") && value === "noAction") continue;
|
|
70041
|
+
if (isDefaultValue(value)) {
|
|
70042
|
+
const isRequiredDomainNamespaces = isArrayEqual(currentPath, ["domain", "namespaces"]);
|
|
70043
|
+
const isDomainNamespaceSlot = matchesPathPattern(currentPath, DOMAIN_NAMESPACE_SLOT_PATTERN);
|
|
70044
|
+
const isRequiredDomainModels = matchesPathPattern(currentPath, DOMAIN_MODELS_CONTAINER_PATTERN);
|
|
70045
|
+
const isRequiredStorageNamespaces = isArrayEqual(currentPath, ["storage", "namespaces"]);
|
|
70046
|
+
const isStorageNamespaceEntries = matchesPathPattern(currentPath, STORAGE_NAMESPACE_ENTRIES_PATTERN);
|
|
70047
|
+
const isRequiredRoots = isArrayEqual(currentPath, ["roots"]);
|
|
70048
|
+
const isRequiredExtensions = isArrayEqual(currentPath, ["extensions"]);
|
|
70049
|
+
const isRequiredCapabilities = isArrayEqual(currentPath, ["capabilities"]);
|
|
70050
|
+
const isRequiredMeta = isArrayEqual(currentPath, ["meta"]);
|
|
70051
|
+
const isRequiredExecutionDefaults = isArrayEqual(currentPath, [
|
|
70052
|
+
"execution",
|
|
70053
|
+
"mutations",
|
|
70054
|
+
"defaults"
|
|
70055
|
+
]);
|
|
70056
|
+
const isExtensionNamespace = currentPath.length === 2 && currentPath[0] === "extensions";
|
|
70057
|
+
const isModelRelations = matchesPathPattern(currentPath, DOMAIN_MODEL_RELATIONS_PATTERN);
|
|
70058
|
+
const isModelStorage = matchesPathPattern(currentPath, DOMAIN_MODEL_STORAGE_PATTERN);
|
|
70059
|
+
const isNullableField = key === "nullable";
|
|
70060
|
+
const isFamilyPreserved = shouldPreserveEmpty?.(currentPath) ?? false;
|
|
70061
|
+
if (!isRequiredDomainNamespaces && !isDomainNamespaceSlot && !isRequiredDomainModels && !isRequiredStorageNamespaces && !isStorageNamespaceEntries && !isRequiredRoots && !isRequiredExtensions && !isRequiredCapabilities && !isRequiredMeta && !isRequiredExecutionDefaults && !isExtensionNamespace && !isModelRelations && !isModelStorage && !isNullableField && !isFamilyPreserved) continue;
|
|
70062
|
+
}
|
|
70063
|
+
result[key] = omitDefaults(value, currentPath, shouldPreserveEmpty);
|
|
70064
|
+
}
|
|
70065
|
+
return result;
|
|
70066
|
+
}
|
|
70067
|
+
function sortObjectKeys(obj) {
|
|
70068
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
70069
|
+
if (Array.isArray(obj)) return obj.map((item) => sortObjectKeys(item));
|
|
70070
|
+
const sorted = {};
|
|
70071
|
+
const keys = Object.keys(obj).sort();
|
|
70072
|
+
for (const key of keys) sorted[key] = sortObjectKeys(obj[key]);
|
|
70073
|
+
return sorted;
|
|
70074
|
+
}
|
|
70075
|
+
function orderTopLevel(obj) {
|
|
70076
|
+
const ordered = {};
|
|
70077
|
+
const remaining = new Set(Object.keys(obj));
|
|
70078
|
+
for (const key of TOP_LEVEL_ORDER) if (remaining.has(key)) {
|
|
70079
|
+
ordered[key] = obj[key];
|
|
70080
|
+
remaining.delete(key);
|
|
70081
|
+
}
|
|
70082
|
+
for (const key of Array.from(remaining).sort()) ordered[key] = obj[key];
|
|
70083
|
+
return ordered;
|
|
70084
|
+
}
|
|
70085
|
+
/**
|
|
70086
|
+
* Object-form variant of {@link canonicalizeContract}. Exported because the
|
|
70087
|
+
* emitter writes the canonical contract through a separate JSON-stringify
|
|
70088
|
+
* pass and consumes the structured object directly.
|
|
70089
|
+
*/
|
|
70090
|
+
function canonicalizeContractToObject(contract, options) {
|
|
70091
|
+
const serialized = options.serializeContract(contract);
|
|
70092
|
+
const withDefaultsOmitted = omitDefaults({
|
|
70093
|
+
...ifDefined("schemaVersion", options.schemaVersion),
|
|
70094
|
+
targetFamily: serialized["targetFamily"],
|
|
70095
|
+
target: serialized["target"],
|
|
70096
|
+
profileHash: serialized["profileHash"],
|
|
70097
|
+
roots: serialized["roots"],
|
|
70098
|
+
domain: serialized["domain"],
|
|
70099
|
+
storage: serialized["storage"],
|
|
70100
|
+
...ifDefined("execution", serialized["execution"]),
|
|
70101
|
+
extensions: serialized["extensions"],
|
|
70102
|
+
capabilities: serialized["capabilities"],
|
|
70103
|
+
...ifDefined("defaultControlPolicy", serialized["defaultControlPolicy"]),
|
|
70104
|
+
meta: serialized["meta"]
|
|
70105
|
+
}, [], options.shouldPreserveEmpty);
|
|
70106
|
+
return orderTopLevel(sortObjectKeys(options.sortStorage ? {
|
|
70107
|
+
...withDefaultsOmitted,
|
|
70108
|
+
storage: options.sortStorage(withDefaultsOmitted["storage"])
|
|
70109
|
+
} : withDefaultsOmitted));
|
|
70110
|
+
}
|
|
70111
|
+
function canonicalizeContract(contract, options) {
|
|
70112
|
+
return JSON.stringify(canonicalizeContractToObject(contract, options), null, 2);
|
|
70113
|
+
}
|
|
70114
|
+
const SCHEMA_VERSION$1 = "1";
|
|
70115
|
+
function omitNamespaceKindsForHash(storage) {
|
|
70116
|
+
if (!isPlainRecord(storage)) return storage;
|
|
70117
|
+
const namespaces = storage["namespaces"];
|
|
70118
|
+
if (!isPlainRecord(namespaces)) return storage;
|
|
70119
|
+
const stripped = {};
|
|
70120
|
+
for (const [nsId, ns] of Object.entries(namespaces)) if (isPlainRecord(ns)) {
|
|
70121
|
+
const { kind: _kind, ...rest } = ns;
|
|
70122
|
+
stripped[nsId] = rest;
|
|
70123
|
+
} else stripped[nsId] = ns;
|
|
70124
|
+
return {
|
|
70125
|
+
...storage,
|
|
70126
|
+
namespaces: stripped
|
|
70127
|
+
};
|
|
70128
|
+
}
|
|
70129
|
+
function sha256(content) {
|
|
70130
|
+
const hash = createHash("sha256");
|
|
70131
|
+
hash.update(content);
|
|
70132
|
+
return hash.digest("hex");
|
|
70133
|
+
}
|
|
70134
|
+
function hashContract(section) {
|
|
70135
|
+
const { shouldPreserveEmpty, sortStorage, ...sectionData } = section;
|
|
70136
|
+
const storageForHash = omitNamespaceKindsForHash(sectionData["storage"] ?? {});
|
|
70137
|
+
return canonicalizeContract(blindCast({
|
|
70138
|
+
targetFamily: sectionData["targetFamily"],
|
|
70139
|
+
target: sectionData["target"],
|
|
70140
|
+
roots: {},
|
|
70141
|
+
domain: { namespaces: {} },
|
|
70142
|
+
execution: sectionData["execution"],
|
|
70143
|
+
extensions: {},
|
|
70144
|
+
capabilities: sectionData["capabilities"] ?? {},
|
|
70145
|
+
meta: {},
|
|
70146
|
+
profileHash: "",
|
|
70147
|
+
...sectionData,
|
|
70148
|
+
storage: storageForHash
|
|
70149
|
+
}), {
|
|
70150
|
+
schemaVersion: SCHEMA_VERSION$1,
|
|
70151
|
+
serializeContract: (c) => castAs(JSON.parse(JSON.stringify(c))),
|
|
70152
|
+
...ifDefined("shouldPreserveEmpty", shouldPreserveEmpty),
|
|
70153
|
+
...ifDefined("sortStorage", sortStorage)
|
|
70154
|
+
});
|
|
70155
|
+
}
|
|
70156
|
+
function computeStorageHash(args) {
|
|
70157
|
+
return blindCast(sha256(hashContract(args)));
|
|
70158
|
+
}
|
|
68408
70159
|
const sqlFamilyEntityTypes = { enum: {
|
|
68409
70160
|
kind: "entity",
|
|
68410
70161
|
discriminator: "enum",
|
|
@@ -68515,13 +70266,18 @@ const sqlFamilyEntityTypes = { enum: {
|
|
|
68515
70266
|
})));
|
|
68516
70267
|
} }
|
|
68517
70268
|
} };
|
|
70269
|
+
const enumTypeBlockAttribute = blockAttribute("type", { positional: [{
|
|
70270
|
+
key: "codecId",
|
|
70271
|
+
type: str()
|
|
70272
|
+
}] });
|
|
68518
70273
|
const sqlFamilyPslBlockDescriptors = { enum: {
|
|
68519
70274
|
kind: "pslBlock",
|
|
68520
70275
|
keyword: "enum",
|
|
68521
70276
|
discriminator: "enum",
|
|
68522
70277
|
name: { required: true },
|
|
68523
70278
|
parameters: {},
|
|
68524
|
-
variadicParameters: true
|
|
70279
|
+
variadicParameters: true,
|
|
70280
|
+
attributes: { type: () => enumTypeBlockAttribute }
|
|
68525
70281
|
} };
|
|
68526
70282
|
/**
|
|
68527
70283
|
* Family-level SQL authoring field presets.
|
|
@@ -68722,6 +70478,24 @@ const NamespaceRawSchema = type({
|
|
|
68722
70478
|
entries: type({ "+": "ignore" })
|
|
68723
70479
|
});
|
|
68724
70480
|
/**
|
|
70481
|
+
* A `contract.json` written before to-one relations recorded `nullable` (rc.9 and earlier)
|
|
70482
|
+
* loads with the flag derived from storage: nullable when any local FK column is nullable or
|
|
70483
|
+
* cannot be resolved.
|
|
70484
|
+
*/
|
|
70485
|
+
function withSqlToOneRelationNullability(contract) {
|
|
70486
|
+
const domain = withDerivedToOneRelationNullability(contract.domain, ({ model, relation }) => {
|
|
70487
|
+
const { ownsForeignKey, columns } = resolveSqlToOneRelationStorage(contract, blindCast(model.storage), relation);
|
|
70488
|
+
return {
|
|
70489
|
+
ownsReference: ownsForeignKey,
|
|
70490
|
+
localFieldNullability: columns.map((column) => column.nullable)
|
|
70491
|
+
};
|
|
70492
|
+
});
|
|
70493
|
+
return {
|
|
70494
|
+
...contract,
|
|
70495
|
+
domain
|
|
70496
|
+
};
|
|
70497
|
+
}
|
|
70498
|
+
/**
|
|
68725
70499
|
* SQL family `ContractSerializer` abstract base. Carries the SQL-shared
|
|
68726
70500
|
* deserialization pipeline:
|
|
68727
70501
|
*
|
|
@@ -68755,7 +70529,7 @@ var SqlContractSerializerBase = class {
|
|
|
68755
70529
|
this.contractSchema = packEntityKinds.length > 0 ? createSqlContractSchema(this.entryKinds) : void 0;
|
|
68756
70530
|
}
|
|
68757
70531
|
deserializeContract(json) {
|
|
68758
|
-
const validated = this.parseSqlContractStructure(json);
|
|
70532
|
+
const validated = withSqlToOneRelationNullability(this.parseSqlContractStructure(json));
|
|
68759
70533
|
const hydrated = this.hydrateSqlStorage(validated);
|
|
68760
70534
|
return this.constructTargetContract(hydrated);
|
|
68761
70535
|
}
|
|
@@ -68959,91 +70733,6 @@ function parseContractMarkerRow(row) {
|
|
|
68959
70733
|
function collectSupportedCodecTypeIds(descriptors) {
|
|
68960
70734
|
return [];
|
|
68961
70735
|
}
|
|
68962
|
-
/**
|
|
68963
|
-
* Generic Result type for representing success or failure outcomes.
|
|
68964
|
-
*
|
|
68965
|
-
* This is the standard way to return "expected failures" as values rather than
|
|
68966
|
-
* throwing exceptions. See docs/Error Handling.md for the full taxonomy.
|
|
68967
|
-
*
|
|
68968
|
-
* Naming rationale:
|
|
68969
|
-
* - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator
|
|
68970
|
-
* - `NotOk` avoids collision with domain types like "Failure" or "Error"
|
|
68971
|
-
* - `failure` property distinguishes from JS Error semantics
|
|
68972
|
-
*/
|
|
68973
|
-
/**
|
|
68974
|
-
* Result class that implements both Ok and NotOk variants.
|
|
68975
|
-
*/
|
|
68976
|
-
var ResultImpl = class ResultImpl {
|
|
68977
|
-
ok;
|
|
68978
|
-
_value;
|
|
68979
|
-
_failure;
|
|
68980
|
-
constructor(ok, valueOrFailure) {
|
|
68981
|
-
this.ok = ok;
|
|
68982
|
-
if (ok) this._value = valueOrFailure;
|
|
68983
|
-
else this._failure = valueOrFailure;
|
|
68984
|
-
Object.freeze(this);
|
|
68985
|
-
}
|
|
68986
|
-
get value() {
|
|
68987
|
-
if (!this.ok) throw new InternalError("Cannot access value on NotOk result");
|
|
68988
|
-
return this._value;
|
|
68989
|
-
}
|
|
68990
|
-
get failure() {
|
|
68991
|
-
if (this.ok) throw new InternalError("Cannot access failure on Ok result");
|
|
68992
|
-
return this._failure;
|
|
68993
|
-
}
|
|
68994
|
-
/**
|
|
68995
|
-
* Creates a successful result.
|
|
68996
|
-
*/
|
|
68997
|
-
static ok(value) {
|
|
68998
|
-
return blindCast(new ResultImpl(true, value));
|
|
68999
|
-
}
|
|
69000
|
-
/**
|
|
69001
|
-
* Creates an unsuccessful result.
|
|
69002
|
-
*/
|
|
69003
|
-
static notOk(failure) {
|
|
69004
|
-
return blindCast(new ResultImpl(false, failure));
|
|
69005
|
-
}
|
|
69006
|
-
/**
|
|
69007
|
-
* Asserts that this result is Ok and returns the value.
|
|
69008
|
-
* Throws if the result is NotOk.
|
|
69009
|
-
*/
|
|
69010
|
-
assertOk() {
|
|
69011
|
-
if (!this.ok) throw new InternalError("Expected Ok result but got NotOk");
|
|
69012
|
-
return this.value;
|
|
69013
|
-
}
|
|
69014
|
-
/**
|
|
69015
|
-
* Asserts that this result is NotOk and returns the failure.
|
|
69016
|
-
* Throws if the result is Ok.
|
|
69017
|
-
*/
|
|
69018
|
-
assertNotOk() {
|
|
69019
|
-
if (this.ok) throw new InternalError("Expected NotOk result but got Ok");
|
|
69020
|
-
return this.failure;
|
|
69021
|
-
}
|
|
69022
|
-
};
|
|
69023
|
-
/**
|
|
69024
|
-
* Creates a successful result.
|
|
69025
|
-
*/
|
|
69026
|
-
function ok$1(value) {
|
|
69027
|
-
return ResultImpl.ok(value);
|
|
69028
|
-
}
|
|
69029
|
-
/**
|
|
69030
|
-
* Creates an unsuccessful result.
|
|
69031
|
-
*/
|
|
69032
|
-
function notOk(failure) {
|
|
69033
|
-
return ResultImpl.notOk(failure);
|
|
69034
|
-
}
|
|
69035
|
-
/**
|
|
69036
|
-
* Singleton for void success results.
|
|
69037
|
-
* Use this for validation checks that don't produce a value.
|
|
69038
|
-
*/
|
|
69039
|
-
const OK_VOID = ResultImpl.ok(void 0);
|
|
69040
|
-
/**
|
|
69041
|
-
* Returns a successful void result.
|
|
69042
|
-
* Use this for validation checks that don't produce a value.
|
|
69043
|
-
*/
|
|
69044
|
-
function okVoid() {
|
|
69045
|
-
return OK_VOID;
|
|
69046
|
-
}
|
|
69047
70736
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
69048
70737
|
function normalizeWindowsPath(input = "") {
|
|
69049
70738
|
if (!input) return input;
|
|
@@ -71133,7 +72822,8 @@ var SqlFamilyDescriptor = class {
|
|
|
71133
72822
|
field: sqlFamilyAuthoringFieldPresets,
|
|
71134
72823
|
type: sqlFamilyAuthoringTypes,
|
|
71135
72824
|
entityTypes: sqlFamilyEntityTypes,
|
|
71136
|
-
pslBlockDescriptors: sqlFamilyPslBlockDescriptors
|
|
72825
|
+
pslBlockDescriptors: sqlFamilyPslBlockDescriptors,
|
|
72826
|
+
attributeSpecs: sqlAttributeSpecs
|
|
71137
72827
|
};
|
|
71138
72828
|
create(stack) {
|
|
71139
72829
|
return createSqlFamilyInstance(stack);
|
|
@@ -71666,614 +73356,6 @@ function runnerFailure(code, summary, options) {
|
|
|
71666
73356
|
}
|
|
71667
73357
|
Object.freeze({ allowedOperationClasses: Object.freeze(["additive"]) });
|
|
71668
73358
|
var control_default = new SqlFamilyDescriptor();
|
|
71669
|
-
/**
|
|
71670
|
-
* Name of the synthesised namespace bucket the framework parser uses for
|
|
71671
|
-
* top-level declarations that appear outside any `namespace { … }` block.
|
|
71672
|
-
* The double-underscore decoration signals that the identifier is parser-
|
|
71673
|
-
* synthesised and never appears in user-authored PSL source — writing
|
|
71674
|
-
* `namespace __unspecified__ { … }` is a parse error.
|
|
71675
|
-
*
|
|
71676
|
-
* Distinct from the IR sentinel `__unbound__`: the PSL bucket describes
|
|
71677
|
-
* syntactic absence at the parser layer; the IR sentinel describes a late-
|
|
71678
|
-
* bound storage slot at the IR layer. Per-target interpreters decide how
|
|
71679
|
-
* (or whether) to map the PSL bucket to the IR sentinel.
|
|
71680
|
-
*/
|
|
71681
|
-
const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
|
|
71682
|
-
/**
|
|
71683
|
-
* Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over
|
|
71684
|
-
* it. The getters are prototype members (non-enumerable), so spreading or
|
|
71685
|
-
* `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.
|
|
71686
|
-
*/
|
|
71687
|
-
var PslNamespaceNode = class {
|
|
71688
|
-
kind = "namespace";
|
|
71689
|
-
name;
|
|
71690
|
-
entries;
|
|
71691
|
-
span;
|
|
71692
|
-
constructor(init) {
|
|
71693
|
-
this.name = init.name;
|
|
71694
|
-
this.entries = init.entries;
|
|
71695
|
-
this.span = init.span;
|
|
71696
|
-
Object.freeze(this);
|
|
71697
|
-
}
|
|
71698
|
-
get models() {
|
|
71699
|
-
return blindCast(Object.values(this.entries["model"] ?? {}));
|
|
71700
|
-
}
|
|
71701
|
-
get compositeTypes() {
|
|
71702
|
-
return blindCast(Object.values(this.entries["compositeType"] ?? {}));
|
|
71703
|
-
}
|
|
71704
|
-
};
|
|
71705
|
-
/** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */
|
|
71706
|
-
function makePslNamespace(init) {
|
|
71707
|
-
return new PslNamespaceNode(init);
|
|
71708
|
-
}
|
|
71709
|
-
/**
|
|
71710
|
-
* Builds the frozen `entries[kind][name]` container from per-kind arrays.
|
|
71711
|
-
* Built-ins key on their PSL keyword; extension blocks key on their `kind`
|
|
71712
|
-
* discriminator. Call this rather than hand-building the literal.
|
|
71713
|
-
*/
|
|
71714
|
-
function makePslNamespaceEntries(models, compositeTypes, extensionBlocks) {
|
|
71715
|
-
const container = {};
|
|
71716
|
-
if (models.length > 0) {
|
|
71717
|
-
const map = {};
|
|
71718
|
-
for (const m of models) map[m.name] = m;
|
|
71719
|
-
container["model"] = Object.freeze(map);
|
|
71720
|
-
}
|
|
71721
|
-
if (compositeTypes.length > 0) {
|
|
71722
|
-
const map = {};
|
|
71723
|
-
for (const ct of compositeTypes) map[ct.name] = ct;
|
|
71724
|
-
container["compositeType"] = Object.freeze(map);
|
|
71725
|
-
}
|
|
71726
|
-
for (const block of extensionBlocks) {
|
|
71727
|
-
const existing = container[block.kind];
|
|
71728
|
-
const newMap = existing ? blindCast({ ...existing }) : {};
|
|
71729
|
-
newMap[block.name] = block;
|
|
71730
|
-
container[block.kind] = Object.freeze(newMap);
|
|
71731
|
-
}
|
|
71732
|
-
return Object.freeze(container);
|
|
71733
|
-
}
|
|
71734
|
-
/**
|
|
71735
|
-
* A token in the red tree. Unlike the green-layer {@link Token} (kind + text
|
|
71736
|
-
* only), a red token also carries its absolute `offset` within the source and a
|
|
71737
|
-
* link back to its `parent` {@link SyntaxNode}, so a cursor anchored on a token
|
|
71738
|
-
* can walk outward (parent, previous/next token, siblings) without re-scanning
|
|
71739
|
-
* from the document root.
|
|
71740
|
-
*/
|
|
71741
|
-
var SyntaxToken = class {
|
|
71742
|
-
green;
|
|
71743
|
-
kind;
|
|
71744
|
-
text;
|
|
71745
|
-
offset;
|
|
71746
|
-
parent;
|
|
71747
|
-
/** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
|
|
71748
|
-
index;
|
|
71749
|
-
constructor(green, offset, parent, index) {
|
|
71750
|
-
this.green = green;
|
|
71751
|
-
this.kind = green.kind;
|
|
71752
|
-
this.text = green.text;
|
|
71753
|
-
this.offset = offset;
|
|
71754
|
-
this.parent = parent;
|
|
71755
|
-
this.index = index;
|
|
71756
|
-
}
|
|
71757
|
-
get textLength() {
|
|
71758
|
-
return this.text.length;
|
|
71759
|
-
}
|
|
71760
|
-
get endOffset() {
|
|
71761
|
-
return this.offset + this.textLength;
|
|
71762
|
-
}
|
|
71763
|
-
/** Whether `offset` falls within this token, inclusive of both ends. */
|
|
71764
|
-
isInside(offset) {
|
|
71765
|
-
return offset >= this.offset && offset <= this.endOffset;
|
|
71766
|
-
}
|
|
71767
|
-
isOutside(offset) {
|
|
71768
|
-
return !this.isInside(offset);
|
|
71769
|
-
}
|
|
71770
|
-
/** The sibling element immediately after this token within its parent. */
|
|
71771
|
-
get nextSiblingOrToken() {
|
|
71772
|
-
return childAt(this.parent, this.index + 1);
|
|
71773
|
-
}
|
|
71774
|
-
/** The sibling element immediately before this token within its parent. */
|
|
71775
|
-
get prevSiblingOrToken() {
|
|
71776
|
-
return childAt(this.parent, this.index - 1);
|
|
71777
|
-
}
|
|
71778
|
-
/** The next token in document order, crossing node boundaries. */
|
|
71779
|
-
get nextToken() {
|
|
71780
|
-
for (let el = climbingNext(this); el !== void 0; el = climbingNext(el)) {
|
|
71781
|
-
const token = firstToken(el);
|
|
71782
|
-
if (token !== void 0) return token;
|
|
71783
|
-
}
|
|
71784
|
-
}
|
|
71785
|
-
/** The previous token in document order, crossing node boundaries. */
|
|
71786
|
-
get prevToken() {
|
|
71787
|
-
for (let el = climbingPrev(this); el !== void 0; el = climbingPrev(el)) {
|
|
71788
|
-
const token = lastToken(el);
|
|
71789
|
-
if (token !== void 0) return token;
|
|
71790
|
-
}
|
|
71791
|
-
}
|
|
71792
|
-
};
|
|
71793
|
-
var TokenAtOffset = class TokenAtOffset {
|
|
71794
|
-
#state;
|
|
71795
|
-
constructor(state) {
|
|
71796
|
-
this.#state = state;
|
|
71797
|
-
}
|
|
71798
|
-
static none() {
|
|
71799
|
-
return new TokenAtOffset({ kind: "none" });
|
|
71800
|
-
}
|
|
71801
|
-
static single(token) {
|
|
71802
|
-
return new TokenAtOffset({
|
|
71803
|
-
kind: "single",
|
|
71804
|
-
token
|
|
71805
|
-
});
|
|
71806
|
-
}
|
|
71807
|
-
static between(left, right) {
|
|
71808
|
-
return new TokenAtOffset({
|
|
71809
|
-
kind: "between",
|
|
71810
|
-
left,
|
|
71811
|
-
right
|
|
71812
|
-
});
|
|
71813
|
-
}
|
|
71814
|
-
get isEmpty() {
|
|
71815
|
-
return this.#state.kind === "none";
|
|
71816
|
-
}
|
|
71817
|
-
get isBetween() {
|
|
71818
|
-
return this.#state.kind === "between";
|
|
71819
|
-
}
|
|
71820
|
-
leftBiased() {
|
|
71821
|
-
switch (this.#state.kind) {
|
|
71822
|
-
case "none": return;
|
|
71823
|
-
case "single": return this.#state.token;
|
|
71824
|
-
case "between": return this.#state.left;
|
|
71825
|
-
}
|
|
71826
|
-
}
|
|
71827
|
-
rightBiased() {
|
|
71828
|
-
switch (this.#state.kind) {
|
|
71829
|
-
case "none": return;
|
|
71830
|
-
case "single": return this.#state.token;
|
|
71831
|
-
case "between": return this.#state.right;
|
|
71832
|
-
}
|
|
71833
|
-
}
|
|
71834
|
-
};
|
|
71835
|
-
var SyntaxNode = class SyntaxNode {
|
|
71836
|
-
green;
|
|
71837
|
-
offset;
|
|
71838
|
-
parent;
|
|
71839
|
-
/** Position within the parent's children, enabling O(1) sibling navigation without rescanning the green layer. */
|
|
71840
|
-
index;
|
|
71841
|
-
constructor(green, offset, parent, index) {
|
|
71842
|
-
this.green = green;
|
|
71843
|
-
this.offset = offset;
|
|
71844
|
-
this.parent = parent;
|
|
71845
|
-
this.index = index;
|
|
71846
|
-
}
|
|
71847
|
-
get kind() {
|
|
71848
|
-
return this.green.kind;
|
|
71849
|
-
}
|
|
71850
|
-
get textLength() {
|
|
71851
|
-
return this.green.textLength;
|
|
71852
|
-
}
|
|
71853
|
-
get endOffset() {
|
|
71854
|
-
return this.offset + this.textLength;
|
|
71855
|
-
}
|
|
71856
|
-
/** Whether `offset` falls within this node, inclusive of both ends. */
|
|
71857
|
-
isInside(offset) {
|
|
71858
|
-
return offset >= this.offset && offset <= this.endOffset;
|
|
71859
|
-
}
|
|
71860
|
-
isOutside(offset) {
|
|
71861
|
-
return !this.isInside(offset);
|
|
71862
|
-
}
|
|
71863
|
-
get firstChild() {
|
|
71864
|
-
return childAt(this, 0);
|
|
71865
|
-
}
|
|
71866
|
-
get lastChild() {
|
|
71867
|
-
const len = this.green.children.length;
|
|
71868
|
-
if (len === 0) return void 0;
|
|
71869
|
-
return childAt(this, len - 1);
|
|
71870
|
-
}
|
|
71871
|
-
get nextSibling() {
|
|
71872
|
-
return this.parent === void 0 ? void 0 : childAt(this.parent, this.index + 1);
|
|
71873
|
-
}
|
|
71874
|
-
get prevSibling() {
|
|
71875
|
-
return this.parent === void 0 ? void 0 : childAt(this.parent, this.index - 1);
|
|
71876
|
-
}
|
|
71877
|
-
/** The sibling element immediately after this node within its parent. */
|
|
71878
|
-
get nextSiblingOrToken() {
|
|
71879
|
-
return this.nextSibling;
|
|
71880
|
-
}
|
|
71881
|
-
/** The sibling element immediately before this node within its parent. */
|
|
71882
|
-
get prevSiblingOrToken() {
|
|
71883
|
-
return this.prevSibling;
|
|
71884
|
-
}
|
|
71885
|
-
/** The first token in this subtree (depth-first), or `undefined` if empty. */
|
|
71886
|
-
get firstToken() {
|
|
71887
|
-
return firstToken(this);
|
|
71888
|
-
}
|
|
71889
|
-
/** The last token in this subtree (depth-first), or `undefined` if empty. */
|
|
71890
|
-
get lastToken() {
|
|
71891
|
-
return lastToken(this);
|
|
71892
|
-
}
|
|
71893
|
-
*children() {
|
|
71894
|
-
let offset = this.offset;
|
|
71895
|
-
let index = 0;
|
|
71896
|
-
for (const child of this.green.children) {
|
|
71897
|
-
yield wrapElement(child, offset, this, index);
|
|
71898
|
-
offset += elementTextLength(child);
|
|
71899
|
-
index++;
|
|
71900
|
-
}
|
|
71901
|
-
}
|
|
71902
|
-
*childNodes() {
|
|
71903
|
-
for (const child of this.children()) if (child instanceof SyntaxNode) yield child;
|
|
71904
|
-
}
|
|
71905
|
-
*ancestors() {
|
|
71906
|
-
let current = this.parent;
|
|
71907
|
-
while (current) {
|
|
71908
|
-
yield current;
|
|
71909
|
-
current = current.parent;
|
|
71910
|
-
}
|
|
71911
|
-
}
|
|
71912
|
-
/** The nearest match, testing this node itself before walking its ancestors. */
|
|
71913
|
-
findAncestor(cast) {
|
|
71914
|
-
const self = cast(this);
|
|
71915
|
-
if (self !== void 0) return self;
|
|
71916
|
-
for (const ancestor of this.ancestors()) {
|
|
71917
|
-
const result = cast(ancestor);
|
|
71918
|
-
if (result !== void 0) return result;
|
|
71919
|
-
}
|
|
71920
|
-
}
|
|
71921
|
-
*descendants() {
|
|
71922
|
-
const stack = [this];
|
|
71923
|
-
for (let el = stack.pop(); el !== void 0; el = stack.pop()) {
|
|
71924
|
-
yield el;
|
|
71925
|
-
if (el instanceof SyntaxNode) {
|
|
71926
|
-
const children = Array.from(el.children());
|
|
71927
|
-
for (let i = children.length - 1; i >= 0; i--) {
|
|
71928
|
-
const child = children[i];
|
|
71929
|
-
if (child !== void 0) stack.push(child);
|
|
71930
|
-
}
|
|
71931
|
-
}
|
|
71932
|
-
}
|
|
71933
|
-
}
|
|
71934
|
-
*tokens() {
|
|
71935
|
-
for (const el of this.descendants()) if (el instanceof SyntaxToken) yield el;
|
|
71936
|
-
}
|
|
71937
|
-
/**
|
|
71938
|
-
* The token(s) at `offset`. The between-two-tokens case (offset exactly on a
|
|
71939
|
-
* token seam) is represented explicitly so callers can left/right bias.
|
|
71940
|
-
*/
|
|
71941
|
-
tokenAtOffset(offset) {
|
|
71942
|
-
return tokenAtOffsetOf(this, offset);
|
|
71943
|
-
}
|
|
71944
|
-
/**
|
|
71945
|
-
* The smallest element fully containing the range `[start, end]`. At a seam
|
|
71946
|
-
* (and for empty ranges) the left-hand element is preferred, matching
|
|
71947
|
-
* {@link containsOffset}'s inclusive span.
|
|
71948
|
-
*/
|
|
71949
|
-
coveringElement(start, end) {
|
|
71950
|
-
let result = this;
|
|
71951
|
-
for (;;) {
|
|
71952
|
-
if (result instanceof SyntaxToken) return result;
|
|
71953
|
-
let next;
|
|
71954
|
-
for (const child of result.children()) if (containsRange(child, start, end)) {
|
|
71955
|
-
next = child;
|
|
71956
|
-
break;
|
|
71957
|
-
}
|
|
71958
|
-
if (next === void 0) return result;
|
|
71959
|
-
result = next;
|
|
71960
|
-
}
|
|
71961
|
-
}
|
|
71962
|
-
};
|
|
71963
|
-
function elementTextLength(el) {
|
|
71964
|
-
return el.type === "token" ? el.text.length : el.textLength;
|
|
71965
|
-
}
|
|
71966
|
-
function elementLength(el) {
|
|
71967
|
-
return el instanceof SyntaxToken ? el.text.length : el.textLength;
|
|
71968
|
-
}
|
|
71969
|
-
/**
|
|
71970
|
-
* Whether `el` contains `offset`. The span is inclusive on both ends so a seam
|
|
71971
|
-
* offset touches both neighbours.
|
|
71972
|
-
*/
|
|
71973
|
-
function containsOffset(el, offset) {
|
|
71974
|
-
const start = el.offset;
|
|
71975
|
-
const len = elementLength(el);
|
|
71976
|
-
return offset >= start && offset <= start + len;
|
|
71977
|
-
}
|
|
71978
|
-
function containsRange(el, start, end) {
|
|
71979
|
-
const elStart = el.offset;
|
|
71980
|
-
const len = elementLength(el);
|
|
71981
|
-
return elStart <= start && end <= elStart + len;
|
|
71982
|
-
}
|
|
71983
|
-
function tokenAtOffsetOf(el, offset) {
|
|
71984
|
-
if (el instanceof SyntaxToken) return TokenAtOffset.single(el);
|
|
71985
|
-
let left;
|
|
71986
|
-
let right;
|
|
71987
|
-
for (const child of el.children()) {
|
|
71988
|
-
if (!containsOffset(child, offset)) continue;
|
|
71989
|
-
if (left === void 0) left = child;
|
|
71990
|
-
else {
|
|
71991
|
-
right = child;
|
|
71992
|
-
break;
|
|
71993
|
-
}
|
|
71994
|
-
}
|
|
71995
|
-
if (left === void 0) return TokenAtOffset.none();
|
|
71996
|
-
if (right === void 0) return tokenAtOffsetOf(left, offset);
|
|
71997
|
-
const leftToken = tokenAtOffsetOf(left, offset).rightBiased();
|
|
71998
|
-
const rightToken = tokenAtOffsetOf(right, offset).leftBiased();
|
|
71999
|
-
if (leftToken !== void 0 && rightToken !== void 0) return TokenAtOffset.between(leftToken, rightToken);
|
|
72000
|
-
if (leftToken !== void 0) return TokenAtOffset.single(leftToken);
|
|
72001
|
-
if (rightToken !== void 0) return TokenAtOffset.single(rightToken);
|
|
72002
|
-
return TokenAtOffset.none();
|
|
72003
|
-
}
|
|
72004
|
-
function firstToken(el) {
|
|
72005
|
-
if (el instanceof SyntaxToken) return el;
|
|
72006
|
-
for (const child of el.children()) {
|
|
72007
|
-
const token = firstToken(child);
|
|
72008
|
-
if (token !== void 0) return token;
|
|
72009
|
-
}
|
|
72010
|
-
}
|
|
72011
|
-
function lastToken(el) {
|
|
72012
|
-
if (el instanceof SyntaxToken) return el;
|
|
72013
|
-
const children = Array.from(el.children());
|
|
72014
|
-
for (let i = children.length - 1; i >= 0; i--) {
|
|
72015
|
-
const child = children[i];
|
|
72016
|
-
if (child !== void 0) {
|
|
72017
|
-
const token = lastToken(child);
|
|
72018
|
-
if (token !== void 0) return token;
|
|
72019
|
-
}
|
|
72020
|
-
}
|
|
72021
|
-
}
|
|
72022
|
-
function climbingNext(el) {
|
|
72023
|
-
let current = el;
|
|
72024
|
-
for (;;) {
|
|
72025
|
-
const parent = current.parent;
|
|
72026
|
-
if (parent === void 0) return void 0;
|
|
72027
|
-
const sibling = childAt(parent, current.index + 1);
|
|
72028
|
-
if (sibling !== void 0) return sibling;
|
|
72029
|
-
current = parent;
|
|
72030
|
-
}
|
|
72031
|
-
}
|
|
72032
|
-
function climbingPrev(el) {
|
|
72033
|
-
let current = el;
|
|
72034
|
-
for (;;) {
|
|
72035
|
-
const parent = current.parent;
|
|
72036
|
-
if (parent === void 0) return void 0;
|
|
72037
|
-
const sibling = childAt(parent, current.index - 1);
|
|
72038
|
-
if (sibling !== void 0) return sibling;
|
|
72039
|
-
current = parent;
|
|
72040
|
-
}
|
|
72041
|
-
}
|
|
72042
|
-
function wrapElement(green, offset, parent, index) {
|
|
72043
|
-
if (green.type === "token") return new SyntaxToken(green, offset, parent, index);
|
|
72044
|
-
return new SyntaxNode(green, offset, parent, index);
|
|
72045
|
-
}
|
|
72046
|
-
function childAt(node, index) {
|
|
72047
|
-
const children = node.green.children;
|
|
72048
|
-
const target = children[index];
|
|
72049
|
-
if (target === void 0) return void 0;
|
|
72050
|
-
let offset = node.offset;
|
|
72051
|
-
for (let i = 0; i < index; i++) {
|
|
72052
|
-
const child = children[i];
|
|
72053
|
-
if (child !== void 0) offset += elementTextLength(child);
|
|
72054
|
-
}
|
|
72055
|
-
return wrapElement(target, offset, node, index);
|
|
72056
|
-
}
|
|
72057
|
-
function findChildToken(node, kind) {
|
|
72058
|
-
for (const child of node.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) return child;
|
|
72059
|
-
}
|
|
72060
|
-
const HEX = /^[0-9a-fA-F]+$/;
|
|
72061
|
-
function decodeFixedHex(raw, start, width) {
|
|
72062
|
-
if (start + width > raw.length) return void 0;
|
|
72063
|
-
const hex = raw.slice(start, start + width);
|
|
72064
|
-
if (!HEX.test(hex)) return void 0;
|
|
72065
|
-
return String.fromCharCode(Number.parseInt(hex, 16));
|
|
72066
|
-
}
|
|
72067
|
-
function decodeStringLiteral(raw) {
|
|
72068
|
-
let out = "";
|
|
72069
|
-
let i = 0;
|
|
72070
|
-
while (i < raw.length) {
|
|
72071
|
-
const ch = raw.charAt(i);
|
|
72072
|
-
if (ch !== "\\" || i + 1 >= raw.length) {
|
|
72073
|
-
out += ch;
|
|
72074
|
-
i++;
|
|
72075
|
-
continue;
|
|
72076
|
-
}
|
|
72077
|
-
const next = raw.charAt(i + 1);
|
|
72078
|
-
switch (next) {
|
|
72079
|
-
case "n":
|
|
72080
|
-
out += "\n";
|
|
72081
|
-
i += 2;
|
|
72082
|
-
continue;
|
|
72083
|
-
case "r":
|
|
72084
|
-
out += "\r";
|
|
72085
|
-
i += 2;
|
|
72086
|
-
continue;
|
|
72087
|
-
case "t":
|
|
72088
|
-
out += " ";
|
|
72089
|
-
i += 2;
|
|
72090
|
-
continue;
|
|
72091
|
-
case "\"":
|
|
72092
|
-
out += "\"";
|
|
72093
|
-
i += 2;
|
|
72094
|
-
continue;
|
|
72095
|
-
case "'":
|
|
72096
|
-
out += "'";
|
|
72097
|
-
i += 2;
|
|
72098
|
-
continue;
|
|
72099
|
-
case "\\":
|
|
72100
|
-
out += "\\";
|
|
72101
|
-
i += 2;
|
|
72102
|
-
continue;
|
|
72103
|
-
case "x": {
|
|
72104
|
-
const decoded = decodeFixedHex(raw, i + 2, 2);
|
|
72105
|
-
if (decoded === void 0) {
|
|
72106
|
-
out += "\\x";
|
|
72107
|
-
i += 2;
|
|
72108
|
-
continue;
|
|
72109
|
-
}
|
|
72110
|
-
out += decoded;
|
|
72111
|
-
i += 4;
|
|
72112
|
-
continue;
|
|
72113
|
-
}
|
|
72114
|
-
case "u": {
|
|
72115
|
-
const decoded = decodeFixedHex(raw, i + 2, 4);
|
|
72116
|
-
if (decoded === void 0) {
|
|
72117
|
-
out += "\\u";
|
|
72118
|
-
i += 2;
|
|
72119
|
-
continue;
|
|
72120
|
-
}
|
|
72121
|
-
out += decoded;
|
|
72122
|
-
i += 6;
|
|
72123
|
-
continue;
|
|
72124
|
-
}
|
|
72125
|
-
default:
|
|
72126
|
-
out += `\\${next}`;
|
|
72127
|
-
i += 2;
|
|
72128
|
-
continue;
|
|
72129
|
-
}
|
|
72130
|
-
}
|
|
72131
|
-
return out;
|
|
72132
|
-
}
|
|
72133
|
-
var StringLiteralExprAst = class StringLiteralExprAst {
|
|
72134
|
-
syntax;
|
|
72135
|
-
constructor(syntax) {
|
|
72136
|
-
this.syntax = syntax;
|
|
72137
|
-
}
|
|
72138
|
-
token() {
|
|
72139
|
-
return findChildToken(this.syntax, "StringLiteral");
|
|
72140
|
-
}
|
|
72141
|
-
value() {
|
|
72142
|
-
const tok = this.token();
|
|
72143
|
-
if (!tok) return void 0;
|
|
72144
|
-
return decodeStringLiteral(tok.text.slice(1, -1));
|
|
72145
|
-
}
|
|
72146
|
-
static cast(node) {
|
|
72147
|
-
return node.kind === "StringLiteralExpr" ? new StringLiteralExprAst(node) : void 0;
|
|
72148
|
-
}
|
|
72149
|
-
};
|
|
72150
|
-
var NumberLiteralExprAst = class NumberLiteralExprAst {
|
|
72151
|
-
syntax;
|
|
72152
|
-
constructor(syntax) {
|
|
72153
|
-
this.syntax = syntax;
|
|
72154
|
-
}
|
|
72155
|
-
token() {
|
|
72156
|
-
return findChildToken(this.syntax, "NumberLiteral");
|
|
72157
|
-
}
|
|
72158
|
-
value() {
|
|
72159
|
-
const tok = this.token();
|
|
72160
|
-
if (!tok) return void 0;
|
|
72161
|
-
return Number(tok.text);
|
|
72162
|
-
}
|
|
72163
|
-
static cast(node) {
|
|
72164
|
-
return node.kind === "NumberLiteralExpr" ? new NumberLiteralExprAst(node) : void 0;
|
|
72165
|
-
}
|
|
72166
|
-
};
|
|
72167
|
-
function nodePslSpan(node, sourceFile) {
|
|
72168
|
-
const start = node.offset;
|
|
72169
|
-
const end = start + node.green.textLength;
|
|
72170
|
-
return {
|
|
72171
|
-
start: offsetToPslPosition(start, sourceFile),
|
|
72172
|
-
end: offsetToPslPosition(end, sourceFile)
|
|
72173
|
-
};
|
|
72174
|
-
}
|
|
72175
|
-
function offsetToPslPosition(offset, sourceFile) {
|
|
72176
|
-
const position = sourceFile.positionAt(offset);
|
|
72177
|
-
return {
|
|
72178
|
-
offset,
|
|
72179
|
-
line: position.line + 1,
|
|
72180
|
-
column: position.character + 1
|
|
72181
|
-
};
|
|
72182
|
-
}
|
|
72183
|
-
const ATTRIBUTE_DIAGNOSTIC_CODE = "PSL_INVALID_ATTRIBUTE_SYNTAX";
|
|
72184
|
-
function leafDiagnostic(ctx, node, message, code = ATTRIBUTE_DIAGNOSTIC_CODE) {
|
|
72185
|
-
return {
|
|
72186
|
-
code,
|
|
72187
|
-
message,
|
|
72188
|
-
sourceId: ctx.sourceId,
|
|
72189
|
-
span: nodePslSpan(node.syntax, ctx.sourceFile)
|
|
72190
|
-
};
|
|
72191
|
-
}
|
|
72192
|
-
function int(opts) {
|
|
72193
|
-
const min = opts?.min;
|
|
72194
|
-
const max = opts?.max;
|
|
72195
|
-
return {
|
|
72196
|
-
kind: "int",
|
|
72197
|
-
label: "integer",
|
|
72198
|
-
parse: (arg, ctx) => {
|
|
72199
|
-
if (arg instanceof NumberLiteralExprAst) {
|
|
72200
|
-
const value = arg.value();
|
|
72201
|
-
if (value !== void 0 && Number.isInteger(value)) {
|
|
72202
|
-
if ((min === void 0 || value >= min) && (max === void 0 || value <= max)) return ok$1(value);
|
|
72203
|
-
return notOk([leafDiagnostic(ctx, arg, rangeMessage(min, max))]);
|
|
72204
|
-
}
|
|
72205
|
-
}
|
|
72206
|
-
return notOk([leafDiagnostic(ctx, arg, "Expected an integer literal")]);
|
|
72207
|
-
}
|
|
72208
|
-
};
|
|
72209
|
-
}
|
|
72210
|
-
function rangeMessage(min, max) {
|
|
72211
|
-
if (min !== void 0 && max !== void 0) return `Expected an integer between ${min} and ${max}`;
|
|
72212
|
-
if (min !== void 0) return `Expected an integer greater than or equal to ${min}`;
|
|
72213
|
-
return `Expected an integer less than or equal to ${max}`;
|
|
72214
|
-
}
|
|
72215
|
-
function num(value) {
|
|
72216
|
-
return {
|
|
72217
|
-
kind: "num",
|
|
72218
|
-
label: value === void 0 ? "number" : String(value),
|
|
72219
|
-
parse: (arg, ctx) => {
|
|
72220
|
-
if (arg instanceof NumberLiteralExprAst) {
|
|
72221
|
-
const parsed = arg.value();
|
|
72222
|
-
if (parsed !== void 0 && (value === void 0 || parsed === value)) return ok$1(parsed);
|
|
72223
|
-
}
|
|
72224
|
-
return notOk([leafDiagnostic(ctx, arg, value === void 0 ? "Expected a number literal" : `Expected ${value}`)]);
|
|
72225
|
-
}
|
|
72226
|
-
};
|
|
72227
|
-
}
|
|
72228
|
-
function oneOf(...alts) {
|
|
72229
|
-
const label = alts.map((alt) => alt.label).join(" | ");
|
|
72230
|
-
return {
|
|
72231
|
-
kind: "oneOf",
|
|
72232
|
-
label,
|
|
72233
|
-
parse: (arg, ctx) => {
|
|
72234
|
-
for (const alt of alts) {
|
|
72235
|
-
const result = alt.parse(arg, ctx);
|
|
72236
|
-
if (result.ok) return ok$1(blindCast(result.value));
|
|
72237
|
-
}
|
|
72238
|
-
return notOk([leafDiagnostic(ctx, arg, `Expected one of: ${label}`)]);
|
|
72239
|
-
}
|
|
72240
|
-
};
|
|
72241
|
-
}
|
|
72242
|
-
function str() {
|
|
72243
|
-
return {
|
|
72244
|
-
kind: "str",
|
|
72245
|
-
label: "string",
|
|
72246
|
-
parse: (arg, ctx) => {
|
|
72247
|
-
if (arg instanceof StringLiteralExprAst) {
|
|
72248
|
-
const value = arg.value();
|
|
72249
|
-
if (value !== void 0) return ok$1(value);
|
|
72250
|
-
}
|
|
72251
|
-
return notOk([leafDiagnostic(ctx, arg, "Expected a string literal")]);
|
|
72252
|
-
}
|
|
72253
|
-
};
|
|
72254
|
-
}
|
|
72255
|
-
function modelAttribute(name, config) {
|
|
72256
|
-
return {
|
|
72257
|
-
level: "model",
|
|
72258
|
-
name,
|
|
72259
|
-
positional: config.positional ?? [],
|
|
72260
|
-
named: config.named ?? {},
|
|
72261
|
-
...config.refine !== void 0 ? { refine: config.refine } : {}
|
|
72262
|
-
};
|
|
72263
|
-
}
|
|
72264
|
-
function optional(type, ...rest) {
|
|
72265
|
-
if (rest.length === 0) return {
|
|
72266
|
-
...type,
|
|
72267
|
-
optional: true,
|
|
72268
|
-
hasDefault: false
|
|
72269
|
-
};
|
|
72270
|
-
return {
|
|
72271
|
-
...type,
|
|
72272
|
-
optional: true,
|
|
72273
|
-
hasDefault: true,
|
|
72274
|
-
defaultValue: rest[0]
|
|
72275
|
-
};
|
|
72276
|
-
}
|
|
72277
73359
|
const INSTANT_NOW_GENERATOR_ID = "instantNow";
|
|
72278
73360
|
function instantNowControlDescriptor() {
|
|
72279
73361
|
return {
|
|
@@ -72292,7 +73374,6 @@ function instantNowControlDescriptor() {
|
|
|
72292
73374
|
}
|
|
72293
73375
|
const PSL_RLS_PREDICATE_NOT_FOR_OPERATION = "PSL_RLS_PREDICATE_NOT_FOR_OPERATION";
|
|
72294
73376
|
const PSL_POLICY_INVALID_MAP = "PSL_POLICY_INVALID_MAP";
|
|
72295
|
-
const PSL_NATIVE_ENUM_INVALID_MAP = "PSL_NATIVE_ENUM_INVALID_MAP";
|
|
72296
73377
|
const PSL_NATIVE_ENUM_BARE_MEMBER = "PSL_NATIVE_ENUM_BARE_MEMBER";
|
|
72297
73378
|
const PSL_EXTENSION_INVALID_VALUE = "PSL_EXTENSION_INVALID_VALUE";
|
|
72298
73379
|
const PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE = "PSL_NATIVE_ENUM_DUPLICATE_MEMBER_VALUE";
|
|
@@ -72441,19 +73522,10 @@ function lowerRlsPolicyFromBlock(block, ctx) {
|
|
|
72441
73522
|
return;
|
|
72442
73523
|
}
|
|
72443
73524
|
const permissive = permissiveRaw !== "false";
|
|
72444
|
-
const mapAttr = block.
|
|
72445
|
-
if (mapAttr) {
|
|
72446
|
-
const
|
|
72447
|
-
|
|
72448
|
-
if (exactName === void 0 || exactName === "") {
|
|
72449
|
-
ctx.diagnostics?.push({
|
|
72450
|
-
code: PSL_POLICY_INVALID_MAP,
|
|
72451
|
-
message: `\`${block.keyword}\` policy "${block.name}" @@map attribute must have a quoted, non-empty policy-name argument`,
|
|
72452
|
-
sourceId: ctx.sourceId ?? "unknown",
|
|
72453
|
-
span: mapAttr.span
|
|
72454
|
-
});
|
|
72455
|
-
return;
|
|
72456
|
-
}
|
|
73525
|
+
const mapAttr = block.attributes["map"];
|
|
73526
|
+
if (mapAttr !== void 0) {
|
|
73527
|
+
const exactName = mapAttr.args["name"];
|
|
73528
|
+
invariant(typeof exactName === "string", "@@map on a policy block parses one string argument");
|
|
72457
73529
|
ctx.warnings?.push(exactNameBodyWarning("policy", exactName));
|
|
72458
73530
|
return new PostgresRlsPolicy({
|
|
72459
73531
|
naming: {
|
|
@@ -72493,20 +73565,11 @@ function lowerRlsPolicyFromBlock(block, ctx) {
|
|
|
72493
73565
|
function lowerNativeEnumFromBlock(block, ctx) {
|
|
72494
73566
|
const sourceId = ctx.sourceId ?? "unknown";
|
|
72495
73567
|
const diagnostics = ctx.diagnostics;
|
|
72496
|
-
const mapAttr = block.
|
|
73568
|
+
const mapAttr = block.attributes["map"];
|
|
72497
73569
|
let typeName = block.name;
|
|
72498
|
-
if (mapAttr) {
|
|
72499
|
-
const
|
|
72500
|
-
|
|
72501
|
-
if (mapped === void 0) {
|
|
72502
|
-
diagnostics?.push({
|
|
72503
|
-
code: PSL_NATIVE_ENUM_INVALID_MAP,
|
|
72504
|
-
message: `native_enum "${block.name}" @@map attribute must have a quoted type-name argument`,
|
|
72505
|
-
sourceId,
|
|
72506
|
-
span: mapAttr.span
|
|
72507
|
-
});
|
|
72508
|
-
return;
|
|
72509
|
-
}
|
|
73570
|
+
if (mapAttr !== void 0) {
|
|
73571
|
+
const mapped = mapAttr.args["name"];
|
|
73572
|
+
invariant(typeof mapped === "string", "@@map on a native_enum block parses one string argument");
|
|
72510
73573
|
typeName = mapped;
|
|
72511
73574
|
}
|
|
72512
73575
|
let memberError = false;
|
|
@@ -72692,6 +73755,18 @@ const policyRequiresRls = {
|
|
|
72692
73755
|
parameter: "target",
|
|
72693
73756
|
attribute: "rls"
|
|
72694
73757
|
};
|
|
73758
|
+
const policyMapAttribute = blockAttribute("map", {
|
|
73759
|
+
positional: [{
|
|
73760
|
+
key: "name",
|
|
73761
|
+
type: str()
|
|
73762
|
+
}],
|
|
73763
|
+
refine: (parsed, ctx, attributeNode) => parsed.name === "" ? [leafDiagnostic(ctx, attributeNode, "@@map policy name must be a non-empty string", PSL_POLICY_INVALID_MAP)] : []
|
|
73764
|
+
});
|
|
73765
|
+
const policyBlockAttributes = { map: () => policyMapAttribute };
|
|
73766
|
+
const nativeEnumMapAttribute = blockAttribute("map", { positional: [{
|
|
73767
|
+
key: "name",
|
|
73768
|
+
type: str()
|
|
73769
|
+
}] });
|
|
72695
73770
|
const postgresAuthoringPslBlockDescriptors = {
|
|
72696
73771
|
policy_select: {
|
|
72697
73772
|
kind: "pslBlock",
|
|
@@ -72704,7 +73779,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72704
73779
|
using: policyPredicateParam,
|
|
72705
73780
|
permissive: policyPermissiveParam
|
|
72706
73781
|
},
|
|
72707
|
-
requiresModelAttribute: policyRequiresRls
|
|
73782
|
+
requiresModelAttribute: policyRequiresRls,
|
|
73783
|
+
attributes: policyBlockAttributes
|
|
72708
73784
|
},
|
|
72709
73785
|
policy_delete: {
|
|
72710
73786
|
kind: "pslBlock",
|
|
@@ -72717,7 +73793,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72717
73793
|
using: policyPredicateParam,
|
|
72718
73794
|
permissive: policyPermissiveParam
|
|
72719
73795
|
},
|
|
72720
|
-
requiresModelAttribute: policyRequiresRls
|
|
73796
|
+
requiresModelAttribute: policyRequiresRls,
|
|
73797
|
+
attributes: policyBlockAttributes
|
|
72721
73798
|
},
|
|
72722
73799
|
policy_insert: {
|
|
72723
73800
|
kind: "pslBlock",
|
|
@@ -72730,7 +73807,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72730
73807
|
withCheck: policyPredicateParam,
|
|
72731
73808
|
permissive: policyPermissiveParam
|
|
72732
73809
|
},
|
|
72733
|
-
requiresModelAttribute: policyRequiresRls
|
|
73810
|
+
requiresModelAttribute: policyRequiresRls,
|
|
73811
|
+
attributes: policyBlockAttributes
|
|
72734
73812
|
},
|
|
72735
73813
|
policy_update: {
|
|
72736
73814
|
kind: "pslBlock",
|
|
@@ -72744,7 +73822,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72744
73822
|
withCheck: policyPredicateParam,
|
|
72745
73823
|
permissive: policyPermissiveParam
|
|
72746
73824
|
},
|
|
72747
|
-
requiresModelAttribute: policyRequiresRls
|
|
73825
|
+
requiresModelAttribute: policyRequiresRls,
|
|
73826
|
+
attributes: policyBlockAttributes
|
|
72748
73827
|
},
|
|
72749
73828
|
policy_all: {
|
|
72750
73829
|
kind: "pslBlock",
|
|
@@ -72758,7 +73837,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72758
73837
|
withCheck: policyPredicateParam,
|
|
72759
73838
|
permissive: policyPermissiveParam
|
|
72760
73839
|
},
|
|
72761
|
-
requiresModelAttribute: policyRequiresRls
|
|
73840
|
+
requiresModelAttribute: policyRequiresRls,
|
|
73841
|
+
attributes: policyBlockAttributes
|
|
72762
73842
|
},
|
|
72763
73843
|
/**
|
|
72764
73844
|
* PSL block descriptor for `native_enum`.
|
|
@@ -72776,7 +73856,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72776
73856
|
discriminator: "native_enum",
|
|
72777
73857
|
name: { required: true },
|
|
72778
73858
|
parameters: {},
|
|
72779
|
-
variadicParameters: true
|
|
73859
|
+
variadicParameters: true,
|
|
73860
|
+
attributes: { map: () => nativeEnumMapAttribute }
|
|
72780
73861
|
},
|
|
72781
73862
|
/**
|
|
72782
73863
|
* PSL block descriptor for `role` (e.g. `role anon {}`). Name-only, no
|
|
@@ -72792,6 +73873,8 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72792
73873
|
parameters: {}
|
|
72793
73874
|
}
|
|
72794
73875
|
};
|
|
73876
|
+
const postgresRlsSpec = modelAttribute("rls", {});
|
|
73877
|
+
const postgresRlsSpecFactory = () => postgresRlsSpec;
|
|
72795
73878
|
/**
|
|
72796
73879
|
* `@@` model attributes contributed by the Postgres target pack.
|
|
72797
73880
|
*
|
|
@@ -72804,7 +73887,7 @@ const postgresAuthoringPslBlockDescriptors = {
|
|
|
72804
73887
|
const postgresAuthoringModelAttributes = { rls: {
|
|
72805
73888
|
kind: "modelAttribute",
|
|
72806
73889
|
attribute: "rls",
|
|
72807
|
-
spec:
|
|
73890
|
+
spec: postgresRlsSpecFactory,
|
|
72808
73891
|
lower: (_parsed, ctx) => ({
|
|
72809
73892
|
key: ctx.storageName,
|
|
72810
73893
|
entity: new PostgresRlsEnablement({
|
|
@@ -76216,103 +77299,6 @@ var PostgresRoleSchemaNode = class PostgresRoleSchemaNode extends SqlSchemaIRNod
|
|
|
76216
77299
|
assertNode(node, "PostgresRoleSchemaNode", PostgresRoleSchemaNode.is);
|
|
76217
77300
|
}
|
|
76218
77301
|
};
|
|
76219
|
-
/**
|
|
76220
|
-
* Stable code emitted by the runtime when an in-flight `execute()`
|
|
76221
|
-
* is cancelled via the per-query `AbortSignal`. The envelope's
|
|
76222
|
-
* `details.phase` distinguishes where the abort was observed:
|
|
76223
|
-
*
|
|
76224
|
-
* - `'encode'` — abort fired during `encodeParams` (SQL) or
|
|
76225
|
-
* `resolveValue` (Mongo).
|
|
76226
|
-
* - `'decode'` — abort fired during `decodeRow` / `decodeField`.
|
|
76227
|
-
* - `'stream'` — abort fired between rows or before any codec call
|
|
76228
|
-
* (already-aborted at entry).
|
|
76229
|
-
* - `'beforeQuery'` / `'beforeExecute'` / `'afterQuery'` /
|
|
76230
|
-
* `'afterExecute'` / `'onRow'` — abort fired on entry to or during
|
|
76231
|
-
* the corresponding middleware phase
|
|
76232
|
-
* (cooperative cancellation per the param-transform seam).
|
|
76233
|
-
*/
|
|
76234
|
-
const RUNTIME_ABORTED = "RUNTIME.ABORTED";
|
|
76235
|
-
/**
|
|
76236
|
-
* Construct a `RUNTIME.ABORTED` envelope. Phase distinguishes where the
|
|
76237
|
-
* abort was observed — codec call sites (`encode` / `decode` / `stream`)
|
|
76238
|
-
* or operation-specific middleware seams, as
|
|
76239
|
-
* enumerated on {@link RuntimeAbortedPhase}. Cause carries
|
|
76240
|
-
* `signal.reason` verbatim from the platform — native abort produces a
|
|
76241
|
-
* `DOMException`, explicit `controller.abort(reason)` produces whatever
|
|
76242
|
-
* the caller passed. No synthesis happens here.
|
|
76243
|
-
*/
|
|
76244
|
-
function runtimeAborted(phase, cause) {
|
|
76245
|
-
const envelope = runtimeError(RUNTIME_ABORTED, `Operation aborted during ${phase}`, { phase });
|
|
76246
|
-
return Object.assign(envelope, { cause });
|
|
76247
|
-
}
|
|
76248
|
-
/**
|
|
76249
|
-
* Throw a phase-tagged `RUNTIME.ABORTED` envelope if the supplied
|
|
76250
|
-
* context is already aborted at the precheck site. Centralises the
|
|
76251
|
-
* `if (ctx.signal?.aborted) throw runtimeAborted(...)` pattern that
|
|
76252
|
-
* every codec dispatch site (and the `beforeExecute` middleware phase)
|
|
76253
|
-
* repeats. Accepts both the framework `CodecCallContext` and the
|
|
76254
|
-
* `RuntimeMiddlewareContext`; both expose `signal?: AbortSignal`.
|
|
76255
|
-
*/
|
|
76256
|
-
function checkAborted(ctx, phase) {
|
|
76257
|
-
if (ctx.signal?.aborted) throw runtimeAborted(phase, ctx.signal.reason);
|
|
76258
|
-
}
|
|
76259
|
-
/**
|
|
76260
|
-
* Race a per-cell `Promise.all` (or any other in-flight work promise) against
|
|
76261
|
-
* the supplied abort signal so the runtime returns `RUNTIME.ABORTED` promptly
|
|
76262
|
-
* even when codec bodies ignore the signal. In-flight bodies that ignore the
|
|
76263
|
-
* signal are abandoned and run to completion in the background — the
|
|
76264
|
-
* cooperative-cancellation contract documented in ADR 204.
|
|
76265
|
-
*
|
|
76266
|
-
* Call sites still SHOULD pre-check `signal.aborted` and short-circuit with
|
|
76267
|
-
* a phase-tagged `RUNTIME.ABORTED` envelope before invoking this helper —
|
|
76268
|
-
* that path is the canonical "aborted at entry" surface and avoids
|
|
76269
|
-
* scheduling the work promise. As a defensive belt-and-braces, this helper
|
|
76270
|
-
* also handles the already-aborted case internally: `AbortSignal` does not
|
|
76271
|
-
* replay past abort events to listeners registered after the abort, so we
|
|
76272
|
-
* inspect `signal.aborted` synchronously and reject with the sentinel
|
|
76273
|
-
* before installing the listener. The rejection is still attributed to the
|
|
76274
|
-
* abort path via the sentinel-identity check.
|
|
76275
|
-
*
|
|
76276
|
-
* Distinguishing the rejection source is load-bearing for AC-ERR4
|
|
76277
|
-
* (`RUNTIME.ENCODE_FAILED` / `RUNTIME.DECODE_FAILED` pass through unchanged).
|
|
76278
|
-
* The semantically equivalent `abortable(signal)` helper in
|
|
76279
|
-
* `@internal/utils` rejects with `signal.reason ?? new DOMException(...)`,
|
|
76280
|
-
* which is not stably distinguishable from a codec-thrown error by identity
|
|
76281
|
-
* alone (a fresh fallback DOMException is allocated per call). We instead
|
|
76282
|
-
* track abort attribution with a unique sentinel: only the `onAbort` listener
|
|
76283
|
-
* installed here ever rejects with the sentinel, so an `error === sentinel`
|
|
76284
|
-
* identity check after the race is unambiguous.
|
|
76285
|
-
*
|
|
76286
|
-
* Lives in `framework-components` (rather than the SQL family, where it
|
|
76287
|
-
* originated in m2) so every family runtime that needs cooperative
|
|
76288
|
-
* cancellation around a codec-dispatch `Promise.all` (SQL encode + decode
|
|
76289
|
-
* today, Mongo encode in m3) shares the same attribution logic.
|
|
76290
|
-
*/
|
|
76291
|
-
async function raceAgainstAbort(work, signal, phase) {
|
|
76292
|
-
if (signal === void 0) return await work;
|
|
76293
|
-
const sentinel = { reason: void 0 };
|
|
76294
|
-
let onAbort;
|
|
76295
|
-
const abortPromise = new Promise((_, reject) => {
|
|
76296
|
-
if (signal.aborted) {
|
|
76297
|
-
sentinel.reason = signal.reason;
|
|
76298
|
-
reject(sentinel);
|
|
76299
|
-
return;
|
|
76300
|
-
}
|
|
76301
|
-
onAbort = () => {
|
|
76302
|
-
sentinel.reason = signal.reason;
|
|
76303
|
-
reject(sentinel);
|
|
76304
|
-
};
|
|
76305
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
76306
|
-
});
|
|
76307
|
-
try {
|
|
76308
|
-
return await Promise.race([work, abortPromise]);
|
|
76309
|
-
} catch (error) {
|
|
76310
|
-
if (error === sentinel) throw runtimeAborted(phase, sentinel.reason);
|
|
76311
|
-
throw error;
|
|
76312
|
-
} finally {
|
|
76313
|
-
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
76314
|
-
}
|
|
76315
|
-
}
|
|
76316
77302
|
function adapterError(code, message, options) {
|
|
76317
77303
|
return structuredError(code, message, options);
|
|
76318
77304
|
}
|
|
@@ -76417,87 +77403,20 @@ function renderLimitOffset(keyword, value, contract, pim) {
|
|
|
76417
77403
|
return `${keyword} ${renderExpr(value, contract, pim)}`;
|
|
76418
77404
|
}
|
|
76419
77405
|
function renderSelect(ast, contract, pim) {
|
|
76420
|
-
const sourcesByRef = collectTableSources(ast);
|
|
76421
77406
|
return [
|
|
76422
|
-
`SELECT ${renderDistinctPrefix(ast.distinct, ast.distinctOn,
|
|
77407
|
+
`SELECT ${renderDistinctPrefix(ast.distinct, ast.distinctOn, contract, pim)}${renderProjection(ast.projection, contract, pim)}`,
|
|
76423
77408
|
ast.from !== void 0 ? `FROM ${renderSource(ast.from, contract, pim)}` : "",
|
|
76424
77409
|
ast.joins?.length ? ast.joins.map((join) => renderJoin(join, contract, pim)).join(" ") : "",
|
|
76425
77410
|
ast.where ? `WHERE ${renderWhere(ast.where, contract, pim)}` : "",
|
|
76426
77411
|
ast.groupBy?.length ? `GROUP BY ${ast.groupBy.map((expr) => renderExpr(expr, contract, pim)).join(", ")}` : "",
|
|
76427
77412
|
ast.having ? `HAVING ${renderWhere(ast.having, contract, pim)}` : "",
|
|
76428
77413
|
ast.orderBy?.length ? `ORDER BY ${ast.orderBy.map((order) => {
|
|
76429
|
-
return `${
|
|
77414
|
+
return `${renderExpr(order.expr, contract, pim)} ${order.dir.toUpperCase()}`;
|
|
76430
77415
|
}).join(", ")}` : "",
|
|
76431
77416
|
renderLimitOffset("LIMIT", ast.limit, contract, pim),
|
|
76432
77417
|
renderLimitOffset("OFFSET", ast.offset, contract, pim)
|
|
76433
77418
|
].filter((part) => part.length > 0).join(" ").trim();
|
|
76434
77419
|
}
|
|
76435
|
-
/**
|
|
76436
|
-
* Map a SELECT's table references (the FROM source and any JOIN sources) to their storage coordinate, keyed by the name a `ColumnRef.table` would carry (the alias when present, otherwise the table name). Derived-table sources are skipped — their columns are projected through a sub-select, not a base storage column, so the enum hook does not apply.
|
|
76437
|
-
*/
|
|
76438
|
-
function collectTableSources(ast) {
|
|
76439
|
-
const sources = /* @__PURE__ */ new Map();
|
|
76440
|
-
const add = (source) => {
|
|
76441
|
-
if (source.kind !== "table-source") return;
|
|
76442
|
-
const ref = source.alias ?? source.name;
|
|
76443
|
-
sources.set(ref, {
|
|
76444
|
-
name: source.name,
|
|
76445
|
-
namespaceId: source.namespaceId
|
|
76446
|
-
});
|
|
76447
|
-
};
|
|
76448
|
-
if (ast.from !== void 0) add(ast.from);
|
|
76449
|
-
for (const join of ast.joins ?? []) add(join.source);
|
|
76450
|
-
return sources;
|
|
76451
|
-
}
|
|
76452
|
-
/**
|
|
76453
|
-
* Ordered, codec-encoded values of the value-set a storage column restricts to, or `undefined` when the referenced column carries no value-set (the common, non-enum case). Resolves the column's storage coordinate from the SELECT's table sources, then the column's `valueSet` ref to the value-set's `values`.
|
|
76454
|
-
*/
|
|
76455
|
-
function allStrings(values) {
|
|
76456
|
-
return values.every((value) => typeof value === "string");
|
|
76457
|
-
}
|
|
76458
|
-
function resolveEnumOrderValues(ref, sourcesByRef, contract) {
|
|
76459
|
-
const source = sourcesByRef.get(ref.table);
|
|
76460
|
-
if (source === void 0 || source.namespaceId === void 0) return;
|
|
76461
|
-
const sourceNs = contract.storage.namespaces[source.namespaceId];
|
|
76462
|
-
const valueSet = (sourceNs !== void 0 ? sourceNs.entries.table?.[source.name]?.columns[ref.column] : void 0)?.valueSet;
|
|
76463
|
-
if (valueSet === void 0) return;
|
|
76464
|
-
const valueSetNs = contract.storage.namespaces[valueSet.namespaceId];
|
|
76465
|
-
return valueSetNs !== void 0 ? valueSetNs.entries.valueSet?.[valueSet.entityName]?.values : void 0;
|
|
76466
|
-
}
|
|
76467
|
-
/**
|
|
76468
|
-
* Ordered values for an unqualified ORDER BY column (an `identifier-ref`, the shape the sql-builder emits for `.orderBy('col')`). Scans every FROM/JOIN source for a column of that name. Resolves only when exactly one source has a column of that name and it carries a value-set; if more than one source has such a column the bare identifier is ambiguous (regardless of which are enum-backed), so it falls through to the plain column rendering.
|
|
76469
|
-
*/
|
|
76470
|
-
function resolveEnumOrderValuesForIdentifier(name, sourcesByRef, contract) {
|
|
76471
|
-
let matchedColumns = 0;
|
|
76472
|
-
let resolved;
|
|
76473
|
-
for (const source of sourcesByRef.values()) {
|
|
76474
|
-
if (source.namespaceId === void 0) continue;
|
|
76475
|
-
const identNs = contract.storage.namespaces[source.namespaceId];
|
|
76476
|
-
const column = identNs !== void 0 ? identNs.entries.table?.[source.name]?.columns[name] : void 0;
|
|
76477
|
-
if (column === void 0) continue;
|
|
76478
|
-
matchedColumns += 1;
|
|
76479
|
-
if (matchedColumns > 1) return;
|
|
76480
|
-
const valueSet = column.valueSet;
|
|
76481
|
-
if (valueSet === void 0) return;
|
|
76482
|
-
const valueSetNs = contract.storage.namespaces[valueSet.namespaceId];
|
|
76483
|
-
resolved = valueSetNs !== void 0 ? valueSetNs.entries.valueSet?.[valueSet.entityName]?.values : void 0;
|
|
76484
|
-
}
|
|
76485
|
-
return resolved;
|
|
76486
|
-
}
|
|
76487
|
-
/**
|
|
76488
|
-
* Render an ORDER BY expression. A column reference onto an enum-restricted column sorts by declaration order via `array_position(ARRAY[…]::text[], <col>)` over the value-set's ordered values (NULLs return `NULL` from `array_position`, sorting per the clause's default NULL handling). Both qualified `column-ref`s and the unqualified `identifier-ref`s the sql-builder emits for `.orderBy('col')` are intercepted. Every other expression renders unchanged.
|
|
76489
|
-
*/
|
|
76490
|
-
function renderOrderByExpr(expr, sourcesByRef, contract, pim) {
|
|
76491
|
-
if (expr.kind === "column-ref") {
|
|
76492
|
-
const orderValues = resolveEnumOrderValues(expr, sourcesByRef, contract);
|
|
76493
|
-
if (orderValues !== void 0 && allStrings(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${renderColumn(expr)})`;
|
|
76494
|
-
}
|
|
76495
|
-
if (expr.kind === "identifier-ref") {
|
|
76496
|
-
const orderValues = resolveEnumOrderValuesForIdentifier(expr.name, sourcesByRef, contract);
|
|
76497
|
-
if (orderValues !== void 0 && allStrings(orderValues)) return `array_position(ARRAY[${orderValues.map((value) => `'${escapeLiteral(value)}'`).join(", ")}]::text[], ${quoteIdentifier(expr.name)})`;
|
|
76498
|
-
}
|
|
76499
|
-
return renderExpr(expr, contract, pim);
|
|
76500
|
-
}
|
|
76501
77420
|
function renderProjection(projection, contract, pim) {
|
|
76502
77421
|
return projection.map((item) => {
|
|
76503
77422
|
const alias = quoteIdentifier(item.alias);
|
|
@@ -76515,8 +77434,8 @@ function renderReturning(items, contract, pim) {
|
|
|
76515
77434
|
return `${renderExpr(item.expr, contract, pim)} AS ${quoteIdentifier(item.alias)}`;
|
|
76516
77435
|
}).join(", ");
|
|
76517
77436
|
}
|
|
76518
|
-
function renderDistinctPrefix(distinct, distinctOn,
|
|
76519
|
-
if (distinctOn && distinctOn.length > 0) return `DISTINCT ON (${distinctOn.map((expr) =>
|
|
77437
|
+
function renderDistinctPrefix(distinct, distinctOn, contract, pim) {
|
|
77438
|
+
if (distinctOn && distinctOn.length > 0) return `DISTINCT ON (${distinctOn.map((expr) => renderExpr(expr, contract, pim)).join(", ")}) `;
|
|
76520
77439
|
if (distinct) return "DISTINCT ";
|
|
76521
77440
|
return "";
|
|
76522
77441
|
}
|
|
@@ -76920,7 +77839,7 @@ function isLegacyMarkerShapeReadError(message) {
|
|
|
76920
77839
|
return normalized.includes("column \"space\" does not exist") || normalized.includes("no such column: space");
|
|
76921
77840
|
}
|
|
76922
77841
|
function errorLegacyMarkerShape(options) {
|
|
76923
|
-
return errorRunnerFailed(`Legacy marker-table shape detected on ${options.markerLocation} (no \`space\` column). Prisma
|
|
77842
|
+
return errorRunnerFailed(`Legacy marker-table shape detected on ${options.markerLocation} (no \`space\` column). Prisma 8 is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. Drop \`${options.markerLocation}\` and re-run \`{bin} db init\` to reinitialise from a clean baseline.`, {
|
|
76924
77843
|
why: options.why,
|
|
76925
77844
|
fix: "Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `{bin} db init` to recreate it with the current per-space schema.",
|
|
76926
77845
|
nextActions: [{
|
|
@@ -79586,28 +80505,31 @@ const postgresDriverDescriptor = {
|
|
|
79586
80505
|
/**
|
|
79587
80506
|
* Renders the checks a Postgres column needs, as opaque predicate text.
|
|
79588
80507
|
*
|
|
79589
|
-
* A
|
|
80508
|
+
* A domain enum has no type-level enforcement, so membership is a
|
|
79590
80509
|
* predicate: `IN` for a scalar, and `<@` containment for an array — an array
|
|
79591
80510
|
* column cannot use `IN` at all (`operator does not exist: text[] = text`),
|
|
79592
80511
|
* and containment additionally rejects NULL elements. Every list column also
|
|
79593
80512
|
* gets an element-non-null check, which no Postgres column type can express.
|
|
79594
80513
|
*
|
|
79595
|
-
*
|
|
79596
|
-
*
|
|
79597
|
-
*
|
|
79598
|
-
* `operator does not exist` this project exists to eliminate. The scalar `IN`
|
|
79599
|
-
* form needs no cast — `varchar = text` resolves on its own.
|
|
80514
|
+
* Array containment casts both operands to `numeric[]` for numeric members or
|
|
80515
|
+
* `text[]` for string members, so different storage types share an operator
|
|
80516
|
+
* without comparing numbers as text. The scalar `IN` form needs no cast.
|
|
79600
80517
|
*/
|
|
79601
80518
|
function postgresRenderCheckExpressions(input) {
|
|
79602
80519
|
const candidates = [];
|
|
79603
80520
|
const column = quoteIdentifier(input.columnName);
|
|
79604
80521
|
if (input.memberValues !== void 0) {
|
|
79605
80522
|
invariant(input.memberValues.length > 0, `check for "${input.tableName}"."${input.columnName}": empty member set; both authoring surfaces reject a member-less enum before rendering`);
|
|
79606
|
-
const members = input.memberValues.map((value) =>
|
|
80523
|
+
const members = input.memberValues.map((value) => {
|
|
80524
|
+
if (typeof value === "string") return `'${escapeLiteral(value)}'`;
|
|
80525
|
+
invariant(Number.isFinite(value), `check for "${input.tableName}"."${input.columnName}": non-finite numeric member`);
|
|
80526
|
+
return String(value);
|
|
80527
|
+
}).join(", ");
|
|
80528
|
+
const arrayType = input.memberValues.every((value) => typeof value === "number") ? "numeric[]" : "text[]";
|
|
79607
80529
|
candidates.push({
|
|
79608
80530
|
kind: "membership",
|
|
79609
80531
|
columnName: input.columnName,
|
|
79610
|
-
expression: input.many ? `${column}
|
|
80532
|
+
expression: input.many ? `${column}::${arrayType} <@ ARRAY[${members}]::${arrayType}` : `${column} IN (${members})`
|
|
79611
80533
|
});
|
|
79612
80534
|
}
|
|
79613
80535
|
if (input.many) candidates.push({
|
|
@@ -79631,6 +80553,7 @@ const postgresIndexTypes = defineIndexTypes().add("btree", { options: type("obje
|
|
|
79631
80553
|
const postgresTargetDescriptorMeta = {
|
|
79632
80554
|
...postgresTargetDescriptorMetaRuntime,
|
|
79633
80555
|
defaultNamespaceId: DEFAULT_NAMESPACE_ID,
|
|
80556
|
+
supportsNamespaces: true,
|
|
79634
80557
|
indexTypes: postgresIndexTypes,
|
|
79635
80558
|
authoring: {
|
|
79636
80559
|
type: postgresAuthoringTypes$1,
|
|
@@ -82719,7 +83642,7 @@ function isNativeEnumSuffixAppend(actualMembers, expectedMembers) {
|
|
|
82719
83642
|
}
|
|
82720
83643
|
/** Operator-worded refusal for a native-enum member change beyond a suffix append (design ruling — tests match this verbatim). */
|
|
82721
83644
|
function nativeEnumMemberChangeRefusal(options) {
|
|
82722
|
-
return `Native enum type "${options.ddlSchemaName}"."${options.typeName}" changed beyond appending new values (contract declares [${options.expectedMembers.join(", ")}], database has [${options.actualMembers.join(", ")}]). Prisma
|
|
83645
|
+
return `Native enum type "${options.ddlSchemaName}"."${options.typeName}" changed beyond appending new values (contract declares [${options.expectedMembers.join(", ")}], database has [${options.actualMembers.join(", ")}]). Prisma 8 does not modify a native enum's existing values (rename, removal, reorder) — see https://pris.ly/d/postgres-native-enums. Author the change manually with \`migration new\`.`;
|
|
82723
83646
|
}
|
|
82724
83647
|
/**
|
|
82725
83648
|
* Managed native-enum issue -> op lowering. A missing declared type creates
|
|
@@ -216768,7 +217691,7 @@ function addRelationField(map, tableName, field) {
|
|
|
216768
217691
|
if (existing) existing.push(field);
|
|
216769
217692
|
else map.set(tableName, [field]);
|
|
216770
217693
|
}
|
|
216771
|
-
const LOCK_DOMAIN = "
|
|
217694
|
+
const LOCK_DOMAIN = "prisma_8.contract.marker";
|
|
216772
217695
|
/**
|
|
216773
217696
|
* Deep clones and freezes a record object to prevent mutation.
|
|
216774
217697
|
* Recursively clones nested objects and arrays to ensure complete isolation.
|
|
@@ -216945,7 +217868,7 @@ var PostgresMigrationRunner = class {
|
|
|
216945
217868
|
if (result.rows.length === 0) return okVoid();
|
|
216946
217869
|
const columns = new Set(result.rows.map((row) => row.column_name));
|
|
216947
217870
|
if (columns.has("space")) return okVoid();
|
|
216948
|
-
return runnerFailure("MIGRATION.LEGACY_MARKER_SHAPE", "Legacy marker-table shape detected on prisma_contract.marker (no `space` column). Prisma
|
|
217871
|
+
return runnerFailure("MIGRATION.LEGACY_MARKER_SHAPE", "Legacy marker-table shape detected on prisma_contract.marker (no `space` column). Prisma 8 is in pre-1.0; the previous transitional auto-migration to the per-space-row schema has been removed. Drop `prisma_contract.marker` and re-run `dbInit` to reinitialise from a clean baseline.", { meta: {
|
|
216949
217872
|
table: "prisma_contract.marker",
|
|
216950
217873
|
columns: [...columns].sort()
|
|
216951
217874
|
} });
|
|
@@ -217394,6 +218317,10 @@ function buildNativeEnumBlock(name, typeName, values) {
|
|
|
217394
218317
|
}],
|
|
217395
218318
|
span: SYNTHETIC_SPAN
|
|
217396
218319
|
}],
|
|
218320
|
+
attributes: name === typeName ? {} : { map: {
|
|
218321
|
+
args: { name: typeName },
|
|
218322
|
+
span: SYNTHETIC_SPAN
|
|
218323
|
+
} },
|
|
217397
218324
|
span: SYNTHETIC_SPAN
|
|
217398
218325
|
};
|
|
217399
218326
|
}
|
|
@@ -217799,7 +218726,7 @@ function buildPolicyBlocks(policiesByTable, modelNameMap, reservedHeads = /* @__
|
|
|
217799
218726
|
const badRole = policy.roles.find((role) => !PSL_IDENTIFIER.test(role));
|
|
217800
218727
|
if (badRole !== void 0) {
|
|
217801
218728
|
const notes = skipNotesByTable.get(tableName) ?? [];
|
|
217802
|
-
notes.push(`// prisma
|
|
218729
|
+
notes.push(`// prisma: skipped policy "${policy.name}": role "${badRole}" is not a valid PSL identifier and role references cannot be escaped`);
|
|
217803
218730
|
skipNotesByTable.set(tableName, notes);
|
|
217804
218731
|
continue;
|
|
217805
218732
|
}
|
|
@@ -217854,6 +218781,10 @@ function buildPolicyBlocks(policiesByTable, modelNameMap, reservedHeads = /* @__
|
|
|
217854
218781
|
}],
|
|
217855
218782
|
span: SYNTHETIC_SPAN
|
|
217856
218783
|
}],
|
|
218784
|
+
attributes: { map: {
|
|
218785
|
+
args: { name: policy.name },
|
|
218786
|
+
span: SYNTHETIC_SPAN
|
|
218787
|
+
} },
|
|
217857
218788
|
span: SYNTHETIC_SPAN
|
|
217858
218789
|
});
|
|
217859
218790
|
}
|
|
@@ -218208,6 +219139,214 @@ function getEmittedArtifactPaths(outputJsonPath) {
|
|
|
218208
219139
|
dtsPath: `${outputJsonPath.slice(0, -5)}.d.ts`
|
|
218209
219140
|
};
|
|
218210
219141
|
}
|
|
219142
|
+
const TYPESCRIPT_IDENTIFIER = /^[$A-Z_a-z][$\w]*$/;
|
|
219143
|
+
function namespacedMemberName(namespaceId, modelName) {
|
|
219144
|
+
return `${namespaceId === "__unbound__" ? "unbound" : namespaceId}_${modelName}`;
|
|
219145
|
+
}
|
|
219146
|
+
function bareMemberName(_namespaceId, modelName) {
|
|
219147
|
+
return modelName;
|
|
219148
|
+
}
|
|
219149
|
+
function claimMemberName(claims, memberName, source) {
|
|
219150
|
+
if (!TYPESCRIPT_IDENTIFIER.test(memberName)) throw emitterError("CONTRACT.MODEL_TYPE_NAME_INVALID", `Emitted model type name "${memberName}" (from ${source}) is not a TypeScript identifier`, {
|
|
219151
|
+
why: "Every entry in the emitted Models namespace is declared as `export type <name>`, so the name must be a TypeScript identifier.",
|
|
219152
|
+
fix: "Rename the namespace or model so that <namespace>_<Model> contains only letters, digits, `$`, and `_`, and does not start with a digit.",
|
|
219153
|
+
meta: {
|
|
219154
|
+
memberName,
|
|
219155
|
+
source
|
|
219156
|
+
}
|
|
219157
|
+
});
|
|
219158
|
+
const existing = claims.get(memberName);
|
|
219159
|
+
if (existing !== void 0) throw emitterError("CONTRACT.MODEL_TYPE_NAME_COLLISION", `Emitted model type name "${memberName}" is produced by both ${existing} and ${source}`, {
|
|
219160
|
+
why: "Every entry in the emitted Models namespace needs a distinct name, formed as <namespace>_<Model>.",
|
|
219161
|
+
fix: "Rename one of the models or namespaces so the two names differ.",
|
|
219162
|
+
meta: {
|
|
219163
|
+
memberName,
|
|
219164
|
+
sources: [existing, source]
|
|
219165
|
+
}
|
|
219166
|
+
});
|
|
219167
|
+
claims.set(memberName, source);
|
|
219168
|
+
}
|
|
219169
|
+
function isPolymorphicBase(model) {
|
|
219170
|
+
return model.discriminator !== void 0 && model.variants !== void 0;
|
|
219171
|
+
}
|
|
219172
|
+
function findModelByName(namespaces, namespaceId, modelName) {
|
|
219173
|
+
return namespaces.find((ns) => ns.namespaceId === namespaceId)?.models.find((m) => m.modelName === modelName);
|
|
219174
|
+
}
|
|
219175
|
+
function findModel(namespaces, ref) {
|
|
219176
|
+
return findModelByName(namespaces, ref.namespace, ref.model);
|
|
219177
|
+
}
|
|
219178
|
+
function requireRelationTarget(namespaces, owner, relationName, ref) {
|
|
219179
|
+
const target = findModel(namespaces, ref);
|
|
219180
|
+
if (target !== void 0) return target;
|
|
219181
|
+
const ownerSource = `${owner.namespaceId}.${owner.modelName}`;
|
|
219182
|
+
throw emitterError("CONTRACT.MODEL_RELATION_TARGET_MISSING", `Relation "${relationName}" on ${ownerSource} targets ${ref.namespace}.${ref.model}, which is not in the contract`, {
|
|
219183
|
+
why: "A same-space relation must point at a model the contract declares; only cross-space relations may reference models outside it.",
|
|
219184
|
+
fix: "Declare the target model in the contract, or mark the relation as cross-space by giving its target a `space`.",
|
|
219185
|
+
meta: {
|
|
219186
|
+
owner: ownerSource,
|
|
219187
|
+
relationName,
|
|
219188
|
+
target: {
|
|
219189
|
+
namespaceId: ref.namespace,
|
|
219190
|
+
modelName: ref.model
|
|
219191
|
+
}
|
|
219192
|
+
}
|
|
219193
|
+
});
|
|
219194
|
+
}
|
|
219195
|
+
function requireBase(namespaces, variant, base) {
|
|
219196
|
+
const found = findModel(namespaces, base);
|
|
219197
|
+
if (found !== void 0) return found;
|
|
219198
|
+
const variantSource = `${variant.namespaceId}.${variant.modelName}`;
|
|
219199
|
+
const baseSource = `${base.namespace}.${base.model}`;
|
|
219200
|
+
throw emitterError("CONTRACT.MODEL_BASE_MISSING", `Model ${variantSource} names base ${baseSource}, which is not in the contract`, {
|
|
219201
|
+
why: "A variant's type is its base's fields plus its own, so the base must be a model the contract declares.",
|
|
219202
|
+
fix: "Declare the base model in the contract, or remove `base` from the variant.",
|
|
219203
|
+
meta: {
|
|
219204
|
+
variant: variantSource,
|
|
219205
|
+
base: baseSource
|
|
219206
|
+
}
|
|
219207
|
+
});
|
|
219208
|
+
}
|
|
219209
|
+
function requireVariant(namespaces, base, variantName) {
|
|
219210
|
+
const variant = findModelByName(namespaces, base.namespaceId, variantName);
|
|
219211
|
+
if (variant !== void 0) return variant;
|
|
219212
|
+
const baseSource = `${base.namespaceId}.${base.modelName}`;
|
|
219213
|
+
throw emitterError("CONTRACT.MODEL_VARIANT_MISSING", `Polymorphic base ${baseSource} names variant "${variantName}", which is not in the contract`, {
|
|
219214
|
+
why: "The Any<Base> union is the union of the variant model types, so every variant a base declares must be a model in the same namespace.",
|
|
219215
|
+
fix: "Declare the variant model in the same namespace as the base, or remove it from the base's variants.",
|
|
219216
|
+
meta: {
|
|
219217
|
+
base: baseSource,
|
|
219218
|
+
variantName
|
|
219219
|
+
}
|
|
219220
|
+
});
|
|
219221
|
+
}
|
|
219222
|
+
function collectFieldLines(ref, resolvers, discriminatorType) {
|
|
219223
|
+
const lines = /* @__PURE__ */ new Map();
|
|
219224
|
+
for (const [fieldName, field] of Object.entries(ref.model.fields)) {
|
|
219225
|
+
const type = discriminatorType !== void 0 && fieldName === discriminatorType.field ? discriminatorType.type : resolveModelFieldType(ref.modelName, fieldName, field, ref.model, resolvers).output;
|
|
219226
|
+
lines.set(fieldName, `${serializeObjectKey(fieldName)}: ${type};`);
|
|
219227
|
+
}
|
|
219228
|
+
return lines;
|
|
219229
|
+
}
|
|
219230
|
+
function hasJoin(relation) {
|
|
219231
|
+
return "on" in relation && relation.on !== void 0;
|
|
219232
|
+
}
|
|
219233
|
+
function relationLine(owner, relationName, relation, index) {
|
|
219234
|
+
if (relation.to.space !== void 0) return void 0;
|
|
219235
|
+
const target = requireRelationTarget(index.namespaces, owner, relationName, relation.to);
|
|
219236
|
+
const targetMember = index.memberNameOf(target.namespaceId, isPolymorphicBase(target.model) ? `Any${target.modelName}` : target.modelName);
|
|
219237
|
+
const key = serializeObjectKey(relationName);
|
|
219238
|
+
if (!hasJoin(relation)) return {
|
|
219239
|
+
line: `${key}: ${relation.cardinality === "1:N" ? `${targetMember}[]` : targetMember};`,
|
|
219240
|
+
hasJoin: false
|
|
219241
|
+
};
|
|
219242
|
+
if (relation.cardinality === "1:N" || relation.cardinality === "N:M") return {
|
|
219243
|
+
line: `${key}: ${targetMember}[];`,
|
|
219244
|
+
hasJoin: true
|
|
219245
|
+
};
|
|
219246
|
+
return {
|
|
219247
|
+
line: `${key}: ${relation.nullable ? `${targetMember} | null` : targetMember};`,
|
|
219248
|
+
hasJoin: true
|
|
219249
|
+
};
|
|
219250
|
+
}
|
|
219251
|
+
function collectRelationLines(ref, index) {
|
|
219252
|
+
const lines = /* @__PURE__ */ new Map();
|
|
219253
|
+
for (const [relationName, relation] of Object.entries(ref.model.relations)) {
|
|
219254
|
+
const rendered = relationLine(ref, relationName, relation, index);
|
|
219255
|
+
if (rendered !== void 0) lines.set(relationName, rendered);
|
|
219256
|
+
}
|
|
219257
|
+
return lines;
|
|
219258
|
+
}
|
|
219259
|
+
function discriminatorUnion(base) {
|
|
219260
|
+
const values = Object.values(base.variants ?? {}).map((v) => serializeValue(v.value));
|
|
219261
|
+
return values.length > 0 ? values.join(" | ") : "never";
|
|
219262
|
+
}
|
|
219263
|
+
function memberLines(ref, index, resolvers) {
|
|
219264
|
+
const base = ref.model.base !== void 0 ? requireBase(index.namespaces, ref, ref.model.base) : void 0;
|
|
219265
|
+
if (base !== void 0 && isPolymorphicBase(base.model)) {
|
|
219266
|
+
const discriminatorField = base.model.discriminator?.field ?? "";
|
|
219267
|
+
const variantValue = base.model.variants?.[ref.modelName]?.value;
|
|
219268
|
+
const discriminatorType = {
|
|
219269
|
+
field: discriminatorField,
|
|
219270
|
+
type: variantValue !== void 0 ? serializeValue(variantValue) : discriminatorUnion(base.model)
|
|
219271
|
+
};
|
|
219272
|
+
return {
|
|
219273
|
+
fieldsByName: new Map([...collectFieldLines(base, resolvers, discriminatorType), ...collectFieldLines(ref, resolvers, void 0)]),
|
|
219274
|
+
relationsByName: new Map([...collectRelationLines(base, index), ...collectRelationLines(ref, index)])
|
|
219275
|
+
};
|
|
219276
|
+
}
|
|
219277
|
+
return {
|
|
219278
|
+
fieldsByName: collectFieldLines(ref, resolvers, isPolymorphicBase(ref.model) ? {
|
|
219279
|
+
field: ref.model.discriminator?.field ?? "",
|
|
219280
|
+
type: discriminatorUnion(ref.model)
|
|
219281
|
+
} : void 0),
|
|
219282
|
+
relationsByName: collectRelationLines(ref, index)
|
|
219283
|
+
};
|
|
219284
|
+
}
|
|
219285
|
+
function renderMember(memberName, lines, hasOwner) {
|
|
219286
|
+
const entries = [...lines.relationsByName];
|
|
219287
|
+
const joinlessLines = entries.filter(([, r]) => !r.hasJoin).map(([, r]) => r.line);
|
|
219288
|
+
const joinedLines = entries.filter(([, r]) => r.hasJoin).map(([, r]) => r.line);
|
|
219289
|
+
const relationNames = entries.filter(([, r]) => r.hasJoin).map(([name]) => name);
|
|
219290
|
+
const phantom = relationNames.length > 0 ? relationNames.map((name) => serializeValue(name)).join(" | ") : "never";
|
|
219291
|
+
return ` export type ${memberName} = {\n${[
|
|
219292
|
+
...lines.fieldsByName.values(),
|
|
219293
|
+
...joinlessLines,
|
|
219294
|
+
...joinedLines,
|
|
219295
|
+
...hasOwner ? [] : [`readonly [RelationKeys]?: ${phantom};`]
|
|
219296
|
+
].map((line) => ` ${line}`).join("\n")}\n };`;
|
|
219297
|
+
}
|
|
219298
|
+
function namespaceModelsOf(contract) {
|
|
219299
|
+
return Object.entries(contract.domain.namespaces).map(([namespaceId, ns]) => ({
|
|
219300
|
+
namespaceId,
|
|
219301
|
+
models: Object.entries(ns.models).map(([modelName, model]) => ({
|
|
219302
|
+
namespaceId,
|
|
219303
|
+
modelName,
|
|
219304
|
+
model
|
|
219305
|
+
}))
|
|
219306
|
+
}));
|
|
219307
|
+
}
|
|
219308
|
+
function generateModelTypesBlock(contract, resolvers, supportsNamespaces) {
|
|
219309
|
+
const memberNameOf = supportsNamespaces ? namespacedMemberName : bareMemberName;
|
|
219310
|
+
const namespaces = namespaceModelsOf(contract);
|
|
219311
|
+
const index = {
|
|
219312
|
+
namespaces,
|
|
219313
|
+
memberNameOf
|
|
219314
|
+
};
|
|
219315
|
+
const claims = /* @__PURE__ */ new Map();
|
|
219316
|
+
for (const ns of namespaces) for (const ref of ns.models) claimMemberName(claims, memberNameOf(ns.namespaceId, ref.modelName), `${ns.namespaceId}.${ref.modelName}`);
|
|
219317
|
+
for (const ns of namespaces) for (const ref of ns.models) {
|
|
219318
|
+
if (!isPolymorphicBase(ref.model)) continue;
|
|
219319
|
+
claimMemberName(claims, memberNameOf(ns.namespaceId, `Any${ref.modelName}`), `${ns.namespaceId}.Any<${ref.modelName}>`);
|
|
219320
|
+
}
|
|
219321
|
+
const members = [];
|
|
219322
|
+
const constantEntries = [];
|
|
219323
|
+
for (const ns of namespaces) {
|
|
219324
|
+
const keys = [];
|
|
219325
|
+
for (const ref of ns.models) {
|
|
219326
|
+
const memberName = memberNameOf(ns.namespaceId, ref.modelName);
|
|
219327
|
+
members.push(renderMember(memberName, memberLines(ref, index, resolvers), ref.model.owner !== void 0));
|
|
219328
|
+
keys.push(`${serializeObjectKey(ref.modelName)}: Models.${memberName};`);
|
|
219329
|
+
}
|
|
219330
|
+
for (const ref of ns.models) {
|
|
219331
|
+
if (!isPolymorphicBase(ref.model)) continue;
|
|
219332
|
+
const unionName = memberNameOf(ns.namespaceId, `Any${ref.modelName}`);
|
|
219333
|
+
const variantMembers = Object.keys(ref.model.variants ?? {}).map((variantName) => {
|
|
219334
|
+
const variant = requireVariant(namespaces, ref, variantName);
|
|
219335
|
+
return memberNameOf(variant.namespaceId, variant.modelName);
|
|
219336
|
+
});
|
|
219337
|
+
members.push(` export type ${unionName} = ${variantMembers.length > 0 ? variantMembers.join(" | ") : "never"};`);
|
|
219338
|
+
keys.push(`${serializeObjectKey(`Any${ref.modelName}`)}: Models.${unionName};`);
|
|
219339
|
+
}
|
|
219340
|
+
if (!supportsNamespaces) {
|
|
219341
|
+
constantEntries.push(...keys.map((key) => ` ${key}`));
|
|
219342
|
+
continue;
|
|
219343
|
+
}
|
|
219344
|
+
const nsKey = serializeObjectKey(ns.namespaceId);
|
|
219345
|
+
const nested = keys.map((key) => ` ${key}`).join("\n");
|
|
219346
|
+
constantEntries.push(keys.length > 0 ? ` ${nsKey}: {\n${nested}\n };` : ` ${nsKey}: {};`);
|
|
219347
|
+
}
|
|
219348
|
+
return `${members.length > 0 ? `export namespace Models {\n${members.join("\n")}\n}` : "export namespace Models {}"}\n\n${`export declare const models: {\n${constantEntries.join("\n")}\n};`}`;
|
|
219349
|
+
}
|
|
218211
219350
|
function generateEnumBlockType(enums) {
|
|
218212
219351
|
return `{ ${Object.entries(enums).map(([name, entry]) => {
|
|
218213
219352
|
const membersType = `readonly [${entry.members.map((m) => `{ readonly name: ${serializeValue(m.name)}; readonly value: ${serializeValue(m.value)} }`).join(", ")}]`;
|
|
@@ -218256,6 +219395,11 @@ function generateContractDts(contract, emitter, codecTypeImports, hashes, option
|
|
|
218256
219395
|
const fieldTypesMaps = generateFieldTypesMapsByNamespace(namespaceEntries.map(([nsId, ns]) => [nsId, ns.models]), codecLookup, resolveFieldTypeParams, resolveFieldValueSet);
|
|
218257
219396
|
const extraTypeExports = emitter.getStorageTypeExports?.(contract, codecLookup);
|
|
218258
219397
|
const contractWrapper = emitter.getContractWrapper("ContractBase", "TypeMaps");
|
|
219398
|
+
const modelTypesBlock = generateModelTypesBlock(contract, {
|
|
219399
|
+
codecLookup,
|
|
219400
|
+
resolveFieldTypeParams,
|
|
219401
|
+
resolveFieldValueSet
|
|
219402
|
+
}, options?.supportsNamespaces ?? true);
|
|
218259
219403
|
return `// ⚠️ GENERATED FILE - DO NOT EDIT
|
|
218260
219404
|
// This file is automatically generated by 'prisma contract emit'.
|
|
218261
219405
|
// To regenerate, run: prisma contract emit
|
|
@@ -218277,7 +219421,10 @@ ${familyTypeAliases}
|
|
|
218277
219421
|
${valueObjectTypeAliases}
|
|
218278
219422
|
export type FieldOutputTypes = ${fieldTypesMaps.output};
|
|
218279
219423
|
export type FieldInputTypes = ${fieldTypesMaps.input};
|
|
218280
|
-
${extraTypeExports ? `${extraTypeExports}\n` : ""}
|
|
219424
|
+
${extraTypeExports ? `${extraTypeExports}\n` : ""}
|
|
219425
|
+
${modelTypesBlock}
|
|
219426
|
+
|
|
219427
|
+
export type TypeMaps = ${typeMapsExpr};
|
|
218281
219428
|
|
|
218282
219429
|
type ContractBase = Omit<
|
|
218283
219430
|
ContractType<${storageType}>,
|
|
@@ -218301,9 +219448,29 @@ ${domainNamespacesType};
|
|
|
218301
219448
|
${contractWrapper}
|
|
218302
219449
|
`;
|
|
218303
219450
|
}
|
|
219451
|
+
/**
|
|
219452
|
+
* The emitter only ever consumes a freshly authored contract, so every same-space to-one relation
|
|
219453
|
+
* must already state whether it is nullable. Hydration of an on-disk contract derives a missing
|
|
219454
|
+
* flag instead; that path never reaches here.
|
|
219455
|
+
*/
|
|
219456
|
+
function requireToOneRelationNullability(contract) {
|
|
219457
|
+
for (const [namespaceId, namespace] of Object.entries(contract.domain.namespaces)) for (const [modelName, model] of Object.entries(namespace.models)) for (const [relationName, relation] of Object.entries(model.relations ?? {})) {
|
|
219458
|
+
if (!("on" in relation && (relation.cardinality === "1:1" || relation.cardinality === "N:1") && relation.to.space === void 0) || typeof relation.nullable === "boolean") continue;
|
|
219459
|
+
throw emitterError("CONTRACT.RELATION_INVALID", `Relation "${relationName}" on model "${namespaceId}:${modelName}" is a ${relation.cardinality} relation and must carry a boolean "nullable"`, {
|
|
219460
|
+
why: "contract.d.ts types a to-one relation as nullable or required from this flag, and the authoring surfaces always set it.",
|
|
219461
|
+
fix: "Author the contract through PSL or the contract builder, which derive the flag from the local fields the relation joins on.",
|
|
219462
|
+
meta: {
|
|
219463
|
+
modelName,
|
|
219464
|
+
relationName,
|
|
219465
|
+
reason: "to-one-nullability-missing"
|
|
219466
|
+
}
|
|
219467
|
+
});
|
|
219468
|
+
}
|
|
219469
|
+
}
|
|
218304
219470
|
const SCHEMA_VERSION = "1";
|
|
218305
219471
|
async function emit(contract, stack, targetFamily, options) {
|
|
218306
219472
|
if (options.outputJsonPath !== void 0) getEmittedArtifactPaths(options.outputJsonPath);
|
|
219473
|
+
requireToOneRelationNullability(contract);
|
|
218307
219474
|
const { codecTypeImports, queryOperationTypeImports, aggregateDescriptors, codecDescriptors } = stack;
|
|
218308
219475
|
const { storageHash } = contract.storage;
|
|
218309
219476
|
const executionHash = contract.execution?.executionHash;
|
|
@@ -218325,7 +219492,8 @@ async function emit(contract, stack, targetFamily, options) {
|
|
|
218325
219492
|
const generateOptions = {
|
|
218326
219493
|
...ifDefined("queryOperationTypeImports", queryOperationTypeImports),
|
|
218327
219494
|
...ifDefined("aggregateDescriptors", aggregateDescriptors),
|
|
218328
|
-
...ifDefined("codecDescriptors", codecDescriptors)
|
|
219495
|
+
...ifDefined("codecDescriptors", codecDescriptors),
|
|
219496
|
+
...ifDefined("supportsNamespaces", options.supportsNamespaces)
|
|
218329
219497
|
};
|
|
218330
219498
|
const contractTypeHashes = {
|
|
218331
219499
|
storageHash,
|
|
@@ -218689,7 +219857,7 @@ function isControlPolicy(value) {
|
|
|
218689
219857
|
* This is the precondition for advancing a contract space's marker without
|
|
218690
219858
|
* any migrations (the declared-state resolution the db-init aggregate
|
|
218691
219859
|
* planner and `migrate` share): only when nothing in the space is
|
|
218692
|
-
* Prisma-
|
|
219860
|
+
* Prisma 8-managed can the storage structure be correct without a
|
|
218693
219861
|
* migration having produced it. Any space that declares a managed element
|
|
218694
219862
|
* but ships no migration graph is an authoring bug and must fail loudly.
|
|
218695
219863
|
*/
|
|
@@ -220867,7 +222035,7 @@ function buildPathNotFoundFailure(spaceId, marker, targetHash) {
|
|
|
220867
222035
|
};
|
|
220868
222036
|
}
|
|
220869
222037
|
/**
|
|
220870
|
-
* Creates a programmatic control client for Prisma
|
|
222038
|
+
* Creates a programmatic control client for Prisma ORM operations.
|
|
220871
222039
|
*
|
|
220872
222040
|
* The client accepts framework component descriptors at creation time,
|
|
220873
222041
|
* manages driver lifecycle via connect()/close(), and exposes domain
|
|
@@ -221355,7 +222523,10 @@ var ControlClientImpl = class {
|
|
|
221355
222523
|
meta: void 0
|
|
221356
222524
|
});
|
|
221357
222525
|
}
|
|
221358
|
-
const result = await emit(deserializedContract, this.stack, this.options.family.emission, {
|
|
222526
|
+
const result = await emit(deserializedContract, this.stack, this.options.family.emission, {
|
|
222527
|
+
serializeContract: (contract) => this.options.target.contractSerializer.serializeContract(contract),
|
|
222528
|
+
...ifDefined("supportsNamespaces", this.options.target.supportsNamespaces)
|
|
222529
|
+
});
|
|
221359
222530
|
onProgress?.({
|
|
221360
222531
|
action: "emit",
|
|
221361
222532
|
kind: "spanEnd",
|
|
@@ -221403,7 +222574,7 @@ function createPostgresControlClient(options = {}) {
|
|
|
221403
222574
|
...ifDefined("extensions", options.extensions)
|
|
221404
222575
|
});
|
|
221405
222576
|
}
|
|
221406
|
-
var version = "0.18.0-dev.
|
|
222577
|
+
var version = "0.18.0-dev.2";
|
|
221407
222578
|
var migration_default = {
|
|
221408
222579
|
from: null,
|
|
221409
222580
|
to: "9e4dbceec6522a4ffb997dfe82c437de70264962803f6a2c63eb196281232b32",
|