@prisma-next/framework-components 0.12.0 → 0.13.0-dev.10
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/authoring.d.mts +2 -2
- package/dist/authoring.mjs +2 -2
- package/dist/{codec-BFOsuHKK.d.mts → codec-DCQAerzB.d.mts} +1 -1
- package/dist/{codec-BFOsuHKK.d.mts.map → codec-DCQAerzB.d.mts.map} +1 -1
- package/dist/codec.d.mts +1 -1
- package/dist/codec.d.mts.map +1 -1
- package/dist/components.d.mts +1 -1
- package/dist/components.mjs +1 -1
- package/dist/components.mjs.map +1 -1
- package/dist/control.d.mts +85 -13
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +89 -7
- package/dist/control.mjs.map +1 -1
- package/dist/{emission-types-CMv_053d.d.mts → emission-types-vfpSTe63.d.mts} +2 -2
- package/dist/{emission-types-CMv_053d.d.mts.map → emission-types-vfpSTe63.d.mts.map} +1 -1
- package/dist/emission.d.mts +3 -3
- package/dist/execution.d.mts +1 -1
- package/dist/execution.d.mts.map +1 -1
- package/dist/execution.mjs +1 -1
- package/dist/{framework-authoring-DcEZ5Lin.mjs → framework-authoring-CnwPJCO4.mjs} +76 -5
- package/dist/framework-authoring-CnwPJCO4.mjs.map +1 -0
- package/dist/framework-authoring-R0TYCkvG.d.mts +380 -0
- package/dist/framework-authoring-R0TYCkvG.d.mts.map +1 -0
- package/dist/{framework-components-CuoUhyB5.d.mts → framework-components-DDQXmW0b.d.mts} +6 -5
- package/dist/{framework-components-CuoUhyB5.d.mts.map → framework-components-DDQXmW0b.d.mts.map} +1 -1
- package/dist/{framework-components-FdqmlGUj.mjs → framework-components-DbCS57go.mjs} +1 -1
- package/dist/{framework-components-FdqmlGUj.mjs.map → framework-components-DbCS57go.mjs.map} +1 -1
- package/dist/ir.d.mts +20 -18
- package/dist/ir.d.mts.map +1 -1
- package/dist/ir.mjs +17 -14
- package/dist/ir.mjs.map +1 -1
- package/dist/{psl-ast-BDXL7iCg.d.mts → psl-ast-Cn50B-UG.d.mts} +90 -18
- package/dist/psl-ast-Cn50B-UG.d.mts.map +1 -0
- package/dist/psl-ast.d.mts +37 -2
- package/dist/psl-ast.d.mts.map +1 -0
- package/dist/psl-ast.mjs +222 -4
- package/dist/psl-ast.mjs.map +1 -1
- package/dist/runtime.d.mts +1 -1
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs.map +1 -1
- package/dist/{types-import-spec-BxI5cSQy.d.mts → types-import-spec-DRKzrJ20.d.mts} +1 -1
- package/dist/{types-import-spec-BxI5cSQy.d.mts.map → types-import-spec-DRKzrJ20.d.mts.map} +1 -1
- package/dist/utils.mjs.map +1 -1
- package/package.json +9 -9
- package/src/control/control-instances.ts +15 -5
- package/src/control/control-migration-types.ts +20 -2
- package/src/control/control-result-types.ts +4 -1
- package/src/control/control-stack.ts +123 -4
- package/src/control/psl-ast.ts +234 -34
- package/src/control/psl-extension-block-validator.ts +324 -0
- package/src/control/verifier-disposition.ts +62 -0
- package/src/exports/authoring.ts +16 -0
- package/src/exports/control.ts +7 -0
- package/src/exports/psl-ast.ts +2 -0
- package/src/ir/namespace.ts +15 -13
- package/src/ir/storage.ts +8 -7
- package/src/shared/framework-authoring.ts +215 -2
- package/src/shared/framework-components.ts +2 -0
- package/src/shared/psl-extension-block.ts +184 -0
- package/dist/framework-authoring-BPPe9C9D.d.mts +0 -183
- package/dist/framework-authoring-BPPe9C9D.d.mts.map +0 -1
- package/dist/framework-authoring-DcEZ5Lin.mjs.map +0 -1
- package/dist/psl-ast-BDXL7iCg.d.mts.map +0 -1
package/dist/ir.mjs
CHANGED
|
@@ -68,22 +68,25 @@ var NamespaceBase = class extends IRNodeBase {};
|
|
|
68
68
|
* value, yielded as {@link EntityCoordinate} tuples with
|
|
69
69
|
* `plane: 'storage'` (the parameter type binds the plane).
|
|
70
70
|
*
|
|
71
|
-
* Iterates each namespace's
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
71
|
+
* Iterates each namespace's `entries` slot maps structurally. Skips
|
|
72
|
+
* non-object `entries`; `id` and `kind` are not walked (`kind` is
|
|
73
|
+
* non-enumerable on concretions). For every entity-kind key under
|
|
74
|
+
* `entries` whose value is a non-null object, yields one coordinate per
|
|
75
|
+
* entity name in that map. No family-specific slot vocabulary is required.
|
|
76
76
|
*/
|
|
77
77
|
function* elementCoordinates(storage) {
|
|
78
|
-
for (const [namespaceId, ns] of Object.entries(storage.namespaces))
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
for (const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {
|
|
79
|
+
const entries = ns.entries;
|
|
80
|
+
if (entries === null || typeof entries !== "object") continue;
|
|
81
|
+
for (const [entityKind, slot] of Object.entries(entries)) {
|
|
82
|
+
if (slot === null || typeof slot !== "object") continue;
|
|
83
|
+
for (const entityName of Object.keys(slot)) yield {
|
|
84
|
+
plane: "storage",
|
|
85
|
+
namespaceId,
|
|
86
|
+
entityKind,
|
|
87
|
+
entityName
|
|
88
|
+
};
|
|
89
|
+
}
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
//#endregion
|
package/dist/ir.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/domain.ts","../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts"],"sourcesContent":["import type { ApplicationDomain } from '@prisma-next/contract/types';\nimport type { EntityCoordinate } from './storage';\n\n/**\n * Lazy walk over every named domain entity in a {@link ApplicationDomain},\n * yielded as {@link EntityCoordinate} tuples with `plane: 'domain'`.\n *\n * Same structural rules as {@link elementCoordinates} over storage: skip\n * scalar `id`; each other object-valued property is an entity-kind slot.\n */\nexport function* domainElementCoordinates(\n domain: Pick<ApplicationDomain, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(domain.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'domain', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n","/**\n * Framework-level IR alphabet.\n *\n * The framework's contribution to Contract IR / Schema IR is a common\n * root for the IR class hierarchy and a freeze affordance. Family\n * abstract bases (e.g. `SqlNode`, `MongoSchemaIRNode`) refine the alphabet\n * for their family shape; targets ship the concrete classes.\n *\n * `kind` is an optional discriminator on the base. Families and leaves\n * that benefit from discriminated-union dispatch declare their own\n * literal `kind` at the level that earns it — Mongo leaves carry\n * per-class literals (`readonly kind = 'mongo-collection' as const`)\n * because Mongo IR has polymorphic walkers; SQL declares a single\n * family-level `kind = 'sql'` on `SqlNode` because SQL IR has no\n * polymorphic dispatch today. No framework consumer dispatches on\n * `IRNode.kind` at the BASE type — every dispatch site narrows\n * through a union of leaves where each leaf carries a literal kind, so\n * requiring `kind` at the base would be unearned. Future leaves that\n * earn polymorphic dispatch override with a required literal at that\n * leaf (e.g. `override readonly kind = 'pack-contributed-kind' as const`).\n *\n * `IRNodeBase` carries no methods: the freeze-and-assign affordance\n * lives in the free `freezeNode` helper below. Keeping `freezeNode` out\n * of the class type means an emitted contract literal type\n * (`{ readonly kind: 'mongo-collection', ... }` or an unkeyed literal\n * like `{ nativeType, codecId, nullable }`) is structurally assignable\n * to its class type — a `protected freeze()` instance method would\n * otherwise leak into the public type surface and require the literal\n * to carry it too.\n *\n * Subclasses construct fields then call `freezeNode(this)` to seal the\n * instance. Frozen instances + plain readonly fields keep IR nodes\n * JSON-clean by construction, so `JSON.stringify(node)` produces canonical\n * JSON without a `toJSON()` method. The `ContractSerializer` SPI handles\n * round-trip from canonical JSON back to typed class instances.\n *\n * The name (`IRNode` / `IRNodeBase`) reflects the dual-hierarchy reality:\n * this base is the common root for both Contract IR and Schema IR class\n * hierarchies, not a Schema-IR-specific alphabet.\n */\n\nexport interface IRNode {\n readonly kind?: string;\n}\n\nexport abstract class IRNodeBase implements IRNode {\n abstract readonly kind?: string;\n}\n\n/**\n * Seal an IR class instance after its constructor has assigned all\n * fields. The free-helper form (rather than a `protected freeze()`\n * instance method) keeps the class type structurally narrow so emitted\n * contract literal types remain assignable to their class types.\n *\n * The helper name stays `freezeNode` — it operates on IR nodes\n * regardless of root naming.\n */\nexport function freezeNode<T extends IRNode>(node: T): T {\n Object.freeze(node);\n return node;\n}\n","import type { StorageNamespace } from '@prisma-next/contract/types';\nimport { type IRNode, IRNodeBase } from './ir-node';\n\n/**\n * Reserved sentinel namespace id for the late-bound storage slot —\n * the slot whose binding the target resolves at connection time\n * rather than at authoring time. Postgres uses it for `search_path`\n * late binding; SQLite uses it for the trivial singleton; Mongo uses\n * it for the connection's `db` binding.\n *\n * Materialised target-side as a singleton subclass of the target's\n * `NamespaceBase` concretion that overrides the namespace's\n * qualifier-emission methods to elide the prefix entirely. Call sites\n * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`\n * — the singleton's overrides drop the qualifier so emitted SQL / Mongo\n * commands look unqualified.\n *\n * The double-underscore decoration marks the id as a framework-reserved\n * coordinate when it appears in a JSON envelope (cold-read-as-reserved\n * — no realistic collision with user-declared namespace names).\n *\n * Encoded as an exported const (rather than scattered string literals)\n * so the sentinel-id invariant is single-sourced: any production-source\n * site that constructs an unbound-namespace singleton imports this\n * constant.\n */\nexport const UNBOUND_NAMESPACE_ID = '__unbound__' as const;\n\n/**\n * Framework-level building block for a \"namespace\" — the database-level\n * grouping under which storage objects (tables, collections, enums, …)\n * reside. Each target's namespace concretion maps the framework concept to\n * a target-native binding:\n *\n * - Postgres: a schema (`CREATE SCHEMA …`); rendered as `\"<schema>\"`.\n * - SQLite: the singleton `UNBOUND_NAMESPACE_ID`; emitted SQL has no qualifier.\n * - Mongo: the connection's `db` field; addressed as a database name.\n *\n * See `UNBOUND_NAMESPACE_ID` above for the sentinel id and the\n * singleton-subclass pattern that materialises it.\n *\n * The framework promises only the coordinate (`id`) — the named storage\n * entities a namespace contains are family-typed (SQL contributes\n * `tables`, Mongo contributes `collections`, future families pick their\n * own native idiom). Generic consumers walking \"all named entries\" go\n * through a family-typed namespace, not the framework `Namespace`.\n *\n * Every namespace concretion (e.g. family-built SQL namespaces,\n * `MongoUnboundNamespace`, target-promoted namespaces like\n * `PostgresSchema`) carries exactly: `id` (enumerable string), `kind`\n * (non-enumerable string discriminator set via `Object.defineProperty`),\n * and one or more entity-kind slot maps — each an own-enumerable property\n * whose key is the entity kind (`tables`, `types`, `collections`,\n * target-pack-contributed slot names) and whose value is a\n * `Record<entityName, EntityIRClass>`. No other own-enumerable data lives\n * on a namespace; non-entity computed data lives on the surrounding storage\n * or contract IR. The framework's `elementCoordinates(storage)` walk relies\n * on this invariant to enumerate entities structurally without\n * family-specific knowledge.\n */\nexport interface Namespace extends IRNode, StorageNamespace {\n readonly kind: string;\n}\n\nexport abstract class NamespaceBase extends IRNodeBase implements Namespace {\n abstract readonly id: string;\n abstract override readonly kind: string;\n}\n","import type { StorageBase } from '@prisma-next/contract/types';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\n\n/**\n * Canonical address for a named entity in Contract IR / Schema IR.\n *\n * `plane` is `'domain' | 'storage'`: which top-level contract plane the\n * entity lives on. Domain-side walks yield `plane: 'domain'` via\n * {@link domainElementCoordinates}; {@link elementCoordinates} over storage\n * yields `plane: 'storage'`.\n *\n * Cross-plane references obey a directional invariant: domain → storage is\n * allowed; storage → domain is forbidden. That rule is enforced by a\n * separate validator, not by constraining this coordinate shape — the\n * coordinate carries the axis the validator checks.\n *\n * Iteration order over namespace properties follows `Object.entries` order;\n * consumers that depend on ordering must sort.\n */\nexport interface EntityCoordinate {\n readonly plane: 'domain' | 'storage';\n readonly namespaceId: string;\n readonly entityKind: string;\n readonly entityName: string;\n}\n\n/**\n * Lazy walk over every named storage entity in a `Storage`-shaped\n * value, yielded as {@link EntityCoordinate} tuples with\n * `plane: 'storage'` (the parameter type binds the plane).\n *\n * Iterates each namespace's own-enumerable properties structurally.\n * Skips `id` (known scalar); `kind` is non-enumerable on namespace\n * concretions and does not appear in `Object.entries`. For every other\n * property whose value is a non-null object, yields one coordinate per\n * entry key in that map. No family-specific slot vocabulary is required.\n */\nexport function* elementCoordinates(\n storage: Pick<StorageBase, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n\n/**\n * Framework-level promise that every Contract IR / Schema IR carries a\n * collection of namespaces keyed by namespace id. Family storage\n * concretions (`SqlStorage`, `MongoStorage`) refine the shape with\n * family-specific fields (tables, collections, enums, …); target\n * concretions add target fields where the family vocabulary doesn't\n * reach.\n *\n * Keeping `namespaces` at the framework layer enforces that every storage\n * object — across any target — is namespace-scoped. The framework can\n * therefore walk the namespace map without knowing the family alphabet, and\n * the `(namespace.id, name)` keying that the verifier and planner depend on\n * is honest at every layer.\n *\n * Extends `IRNode` so the framework's IR-walking surfaces (verifiers,\n * serializers) can dispatch on `Storage`-typed slots through the same\n * IR-node alphabet as every other node — the structural dual already\n * holds in code (every concrete storage class extends an IR-node base);\n * the interface promotion makes the typing honest.\n *\n * **Persisted envelope shape is target-owned, not framework-promised.**\n * Whether the `namespaces` map appears in the on-disk JSON envelope is\n * a per-target decision made by `ContractSerializer.serializeContract`.\n * Some targets emit a JSON-clean namespace shape that round-trips\n * through `JSON.stringify` cleanly (SQL today via the family-layer\n * identity serializer); others ship runtime-only fields on their\n * namespace concretions and override `serializeContract` to strip\n * them (Mongo). Future open (F16): extend the per-target\n * `ContractSerializer` integration-test surface with an explicit\n * envelope-shape assertion for each target, so the strip-vs-pass-through\n * choice is locked at test time rather than implied by the override\n * presence/absence. Earned by PR2's per-target namespace lift, when\n * `PostgresSchema` / `SqliteUnboundDatabase` start carrying\n * target-specific fields.\n */\nexport interface Storage extends IRNode {\n readonly namespaces: Readonly<Record<string, Namespace>>;\n}\n"],"mappings":";;;;;;;;AAUA,UAAiB,yBACf,QAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,OAAO,UAAU,GAC9D,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,EAAE,GAAG;EACnD,IAAI,eAAe,MAAM;EACzB,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;EAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;GAAE,OAAO;GAAU;GAAa;GAAY;EAAW;CAEjE;AAEJ;;;ACuBA,IAAsB,aAAtB,MAAmD,CAEnD;;;;;;;;;;AAWA,SAAgB,WAA6B,MAAY;CACvD,OAAO,OAAO,IAAI;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,MAAa,uBAAuB;AAsCpC,IAAsB,gBAAtB,cAA4C,WAAgC,CAG5E;;;;;;;;;;;;;;AC7BA,UAAiB,mBACf,SAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAC/D,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,EAAE,GAAG;EACnD,IAAI,eAAe,MAAM;EACzB,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;EAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;GAAE,OAAO;GAAW;GAAa;GAAY;EAAW;CAElE;AAEJ"}
|
|
1
|
+
{"version":3,"file":"ir.mjs","names":[],"sources":["../src/ir/domain.ts","../src/ir/ir-node.ts","../src/ir/namespace.ts","../src/ir/storage.ts"],"sourcesContent":["import type { ApplicationDomain } from '@prisma-next/contract/types';\nimport type { EntityCoordinate } from './storage';\n\n/**\n * Lazy walk over every named domain entity in a {@link ApplicationDomain},\n * yielded as {@link EntityCoordinate} tuples with `plane: 'domain'`.\n *\n * Same structural rules as {@link elementCoordinates} over storage: skip\n * scalar `id`; each other object-valued property is an entity-kind slot.\n */\nexport function* domainElementCoordinates(\n domain: Pick<ApplicationDomain, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(domain.namespaces)) {\n for (const [entityKind, slot] of Object.entries(ns)) {\n if (entityKind === 'id') continue;\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'domain', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n","/**\n * Framework-level IR alphabet.\n *\n * The framework's contribution to Contract IR / Schema IR is a common\n * root for the IR class hierarchy and a freeze affordance. Family\n * abstract bases (e.g. `SqlNode`, `MongoSchemaIRNode`) refine the alphabet\n * for their family shape; targets ship the concrete classes.\n *\n * `kind` is an optional discriminator on the base. Families and leaves\n * that benefit from discriminated-union dispatch declare their own\n * literal `kind` at the level that earns it — Mongo leaves carry\n * per-class literals (`readonly kind = 'mongo-collection' as const`)\n * because Mongo IR has polymorphic walkers; SQL declares a single\n * family-level `kind = 'sql'` on `SqlNode` because SQL IR has no\n * polymorphic dispatch today. No framework consumer dispatches on\n * `IRNode.kind` at the BASE type — every dispatch site narrows\n * through a union of leaves where each leaf carries a literal kind, so\n * requiring `kind` at the base would be unearned. Future leaves that\n * earn polymorphic dispatch override with a required literal at that\n * leaf (e.g. `override readonly kind = 'pack-contributed-kind' as const`).\n *\n * `IRNodeBase` carries no methods: the freeze-and-assign affordance\n * lives in the free `freezeNode` helper below. Keeping `freezeNode` out\n * of the class type means an emitted contract literal type\n * (`{ readonly kind: 'mongo-collection', ... }` or an unkeyed literal\n * like `{ nativeType, codecId, nullable }`) is structurally assignable\n * to its class type — a `protected freeze()` instance method would\n * otherwise leak into the public type surface and require the literal\n * to carry it too.\n *\n * Subclasses construct fields then call `freezeNode(this)` to seal the\n * instance. Frozen instances + plain readonly fields keep IR nodes\n * JSON-clean by construction, so `JSON.stringify(node)` produces canonical\n * JSON without a `toJSON()` method. The `ContractSerializer` SPI handles\n * round-trip from canonical JSON back to typed class instances.\n *\n * The name (`IRNode` / `IRNodeBase`) reflects the dual-hierarchy reality:\n * this base is the common root for both Contract IR and Schema IR class\n * hierarchies, not a Schema-IR-specific alphabet.\n */\n\nexport interface IRNode {\n readonly kind?: string;\n}\n\nexport abstract class IRNodeBase implements IRNode {\n abstract readonly kind?: string;\n}\n\n/**\n * Seal an IR class instance after its constructor has assigned all\n * fields. The free-helper form (rather than a `protected freeze()`\n * instance method) keeps the class type structurally narrow so emitted\n * contract literal types remain assignable to their class types.\n *\n * The helper name stays `freezeNode` — it operates on IR nodes\n * regardless of root naming.\n */\nexport function freezeNode<T extends IRNode>(node: T): T {\n Object.freeze(node);\n return node;\n}\n","import type { StorageNamespace } from '@prisma-next/contract/types';\nimport { type IRNode, IRNodeBase } from './ir-node';\n\n/**\n * Reserved sentinel namespace id for the late-bound storage slot —\n * the slot whose binding the target resolves at connection time\n * rather than at authoring time. Postgres uses it for `search_path`\n * late binding; SQLite uses it for the trivial singleton; Mongo uses\n * it for the connection's `db` binding.\n *\n * Materialised target-side as a singleton subclass of the target's\n * `NamespaceBase` concretion that overrides the namespace's\n * qualifier-emission methods to elide the prefix entirely. Call sites\n * stay polymorphic and never branch on `id === UNBOUND_NAMESPACE_ID`\n * — the singleton's overrides drop the qualifier so emitted SQL / Mongo\n * commands look unqualified.\n *\n * The double-underscore decoration marks the id as a framework-reserved\n * coordinate when it appears in a JSON envelope (cold-read-as-reserved\n * — no realistic collision with user-declared namespace names).\n *\n * Encoded as an exported const (rather than scattered string literals)\n * so the sentinel-id invariant is single-sourced: any production-source\n * site that constructs an unbound-namespace singleton imports this\n * constant.\n */\nexport const UNBOUND_NAMESPACE_ID = '__unbound__' as const;\n\n/**\n * Framework-level building block for a \"namespace\" — the database-level\n * grouping under which storage objects (tables, collections, enums, …)\n * reside. Each target's namespace concretion maps the framework concept to\n * a target-native binding:\n *\n * - Postgres: a schema (`CREATE SCHEMA …`); rendered as `\"<schema>\"`.\n * - SQLite: the singleton `UNBOUND_NAMESPACE_ID`; emitted SQL has no qualifier.\n * - Mongo: the connection's `db` field; addressed as a database name.\n *\n * See `UNBOUND_NAMESPACE_ID` above for the sentinel id and the\n * singleton-subclass pattern that materialises it.\n *\n * The framework promises only the coordinate (`id`) — the named storage\n * entities a namespace contains are family-typed (SQL contributes\n * `table` / `type`, Mongo contributes `collection`, future families pick\n * their own native idiom under `entries`). Generic consumers walking \"all\n * named entries\" go through a family-typed namespace, not the framework\n * `Namespace`.\n *\n * Every namespace concretion (e.g. family-built SQL namespaces,\n * `MongoUnboundNamespace`, target-promoted namespaces like\n * `PostgresSchema`) carries exactly: `id` (enumerable string),\n * `entries` (frozen object holding entity-kind slot maps), and `kind`\n * (non-enumerable string discriminator set via `Object.defineProperty`).\n * Each slot map under `entries` uses a singular essence key (`table`,\n * `type`, `collection`, …) mapping entity names to IR classes. No other\n * own-enumerable data lives on a namespace; non-entity computed data lives\n * on the surrounding storage or contract IR. The framework's\n * `elementCoordinates(storage)` walk relies on this invariant to enumerate\n * entities structurally without family-specific knowledge.\n */\nexport interface Namespace extends IRNode, StorageNamespace {\n readonly kind: string;\n readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n}\n\nexport abstract class NamespaceBase extends IRNodeBase implements Namespace {\n abstract readonly id: string;\n abstract readonly entries: Readonly<Record<string, Readonly<Record<string, unknown>>>>;\n abstract override readonly kind: string;\n}\n","import type { StorageBase } from '@prisma-next/contract/types';\nimport type { IRNode } from './ir-node';\nimport type { Namespace } from './namespace';\n\n/**\n * Canonical address for a named entity in Contract IR / Schema IR.\n *\n * `plane` is `'domain' | 'storage'`: which top-level contract plane the\n * entity lives on. Domain-side walks yield `plane: 'domain'` via\n * {@link domainElementCoordinates}; {@link elementCoordinates} over storage\n * yields `plane: 'storage'`.\n *\n * Cross-plane references obey a directional invariant: domain → storage is\n * allowed; storage → domain is forbidden. That rule is enforced by a\n * separate validator, not by constraining this coordinate shape — the\n * coordinate carries the axis the validator checks.\n *\n * Iteration order over namespace properties follows `Object.entries` order;\n * consumers that depend on ordering must sort.\n */\nexport interface EntityCoordinate {\n readonly plane: 'domain' | 'storage';\n readonly namespaceId: string;\n readonly entityKind: string;\n readonly entityName: string;\n}\n\n/**\n * Lazy walk over every named storage entity in a `Storage`-shaped\n * value, yielded as {@link EntityCoordinate} tuples with\n * `plane: 'storage'` (the parameter type binds the plane).\n *\n * Iterates each namespace's `entries` slot maps structurally. Skips\n * non-object `entries`; `id` and `kind` are not walked (`kind` is\n * non-enumerable on concretions). For every entity-kind key under\n * `entries` whose value is a non-null object, yields one coordinate per\n * entity name in that map. No family-specific slot vocabulary is required.\n */\nexport function* elementCoordinates(\n storage: Pick<StorageBase, 'namespaces'>,\n): Generator<EntityCoordinate> {\n for (const [namespaceId, ns] of Object.entries(storage.namespaces)) {\n const entries = ns.entries;\n if (entries === null || typeof entries !== 'object') continue;\n for (const [entityKind, slot] of Object.entries(entries)) {\n if (slot === null || typeof slot !== 'object') continue;\n for (const entityName of Object.keys(slot)) {\n yield { plane: 'storage', namespaceId, entityKind, entityName };\n }\n }\n }\n}\n\n/**\n * Framework-level promise that every Contract IR / Schema IR carries a\n * collection of namespaces keyed by namespace id. Family storage\n * concretions (`SqlStorage`, `MongoStorage`) refine the shape with\n * family-specific fields (tables, collections, enums, …); target\n * concretions add target fields where the family vocabulary doesn't\n * reach.\n *\n * Keeping `namespaces` at the framework layer enforces that every storage\n * object — across any target — is namespace-scoped. The framework can\n * therefore walk the namespace map without knowing the family alphabet, and\n * the `(namespace.id, name)` keying that the verifier and planner depend on\n * is honest at every layer.\n *\n * Extends `IRNode` so the framework's IR-walking surfaces (verifiers,\n * serializers) can dispatch on `Storage`-typed slots through the same\n * IR-node alphabet as every other node — the structural dual already\n * holds in code (every concrete storage class extends an IR-node base);\n * the interface promotion makes the typing honest.\n *\n * **Persisted envelope shape is target-owned, not framework-promised.**\n * Whether the `namespaces` map appears in the on-disk JSON envelope is\n * a per-target decision made by `ContractSerializer.serializeContract`.\n * Some targets emit a JSON-clean namespace shape that round-trips\n * through `JSON.stringify` cleanly (SQL today via the family-layer\n * identity serializer); others ship runtime-only fields on their\n * namespace concretions and override `serializeContract` to strip\n * them (Mongo). Future open (F16): extend the per-target\n * `ContractSerializer` integration-test surface with an explicit\n * envelope-shape assertion for each target, so the strip-vs-pass-through\n * choice is locked at test time rather than implied by the override\n * presence/absence. Earned by PR2's per-target namespace lift, when\n * `PostgresSchema` / `SqliteUnboundDatabase` start carrying\n * target-specific fields.\n */\nexport interface Storage extends IRNode {\n readonly namespaces: Readonly<Record<string, Namespace>>;\n}\n"],"mappings":";;;;;;;;AAUA,UAAiB,yBACf,QAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,OAAO,UAAU,GAC9D,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,EAAE,GAAG;EACnD,IAAI,eAAe,MAAM;EACzB,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;EAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;GAAE,OAAO;GAAU;GAAa;GAAY;EAAW;CAEjE;AAEJ;;;ACuBA,IAAsB,aAAtB,MAAmD,CAEnD;;;;;;;;;;AAWA,SAAgB,WAA6B,MAAY;CACvD,OAAO,OAAO,IAAI;CAClB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,MAAa,uBAAuB;AAuCpC,IAAsB,gBAAtB,cAA4C,WAAgC,CAI5E;;;;;;;;;;;;;;AC/BA,UAAiB,mBACf,SAC6B;CAC7B,KAAK,MAAM,CAAC,aAAa,OAAO,OAAO,QAAQ,QAAQ,UAAU,GAAG;EAClE,MAAM,UAAU,GAAG;EACnB,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU;EACrD,KAAK,MAAM,CAAC,YAAY,SAAS,OAAO,QAAQ,OAAO,GAAG;GACxD,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;GAC/C,KAAK,MAAM,cAAc,OAAO,KAAK,IAAI,GACvC,MAAM;IAAE,OAAO;IAAW;IAAa;IAAY;GAAW;EAElE;CACF;AACF"}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
+
import { G as PslSpan, L as PslDiagnosticCode, R as PslExtensionBlock, m as AuthoringPslBlockDescriptorNamespace } from "./framework-authoring-R0TYCkvG.mjs";
|
|
2
|
+
import { c as CodecLookup } from "./codec-DCQAerzB.mjs";
|
|
3
|
+
|
|
1
4
|
//#region src/control/psl-ast.d.ts
|
|
2
|
-
interface PslPosition {
|
|
3
|
-
readonly offset: number;
|
|
4
|
-
readonly line: number;
|
|
5
|
-
readonly column: number;
|
|
6
|
-
}
|
|
7
|
-
interface PslSpan {
|
|
8
|
-
readonly start: PslPosition;
|
|
9
|
-
readonly end: PslPosition;
|
|
10
|
-
}
|
|
11
|
-
type PslDiagnosticCode = 'PSL_UNTERMINATED_BLOCK' | 'PSL_UNSUPPORTED_TOP_LEVEL_BLOCK' | 'PSL_INVALID_NAMESPACE_BLOCK' | 'PSL_INVALID_ATTRIBUTE_SYNTAX' | 'PSL_INVALID_MODEL_MEMBER' | 'PSL_UNSUPPORTED_MODEL_ATTRIBUTE' | 'PSL_UNSUPPORTED_FIELD_ATTRIBUTE' | 'PSL_INVALID_RELATION_ATTRIBUTE' | 'PSL_INVALID_REFERENTIAL_ACTION' | 'PSL_INVALID_DEFAULT_VALUE' | 'PSL_INVALID_ENUM_MEMBER' | 'PSL_INVALID_TYPES_MEMBER' | 'PSL_INVALID_QUALIFIED_TYPE';
|
|
12
5
|
interface PslDiagnostic {
|
|
13
6
|
readonly code: PslDiagnosticCode;
|
|
14
7
|
readonly message: string;
|
|
@@ -55,10 +48,19 @@ type PslFieldAttribute = PslAttribute;
|
|
|
55
48
|
interface PslField {
|
|
56
49
|
readonly kind: 'field';
|
|
57
50
|
readonly name: string;
|
|
58
|
-
/** Unqualified type name, e.g. `"User"` for both `User` and `auth.User`. */
|
|
51
|
+
/** Unqualified type name, e.g. `"User"` for both `User`, `auth.User`, and `supabase:auth.User`. */
|
|
59
52
|
readonly typeName: string;
|
|
60
|
-
/** Namespace qualifier from a dot-qualified type reference, e.g. `"auth"` for `auth.User`. Absent for unqualified types. */
|
|
53
|
+
/** Namespace qualifier from a dot-qualified type reference, e.g. `"auth"` for `auth.User` or `supabase:auth.User`. Absent for unqualified types. */
|
|
61
54
|
readonly typeNamespaceId?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Contract-space qualifier from a colon-prefix type reference, e.g. `"supabase"` for
|
|
57
|
+
* `supabase:auth.User` or `supabase:User`. Absent for local (same-space) type references.
|
|
58
|
+
*
|
|
59
|
+
* When present, the field references a model from a different contract space. The namespace
|
|
60
|
+
* (`typeNamespaceId`) and model name (`typeName`) identify the target within that space.
|
|
61
|
+
* Physical table resolution against the extension contract is deferred to the aggregate stage (M3).
|
|
62
|
+
*/
|
|
63
|
+
readonly typeContractSpaceId?: string;
|
|
62
64
|
readonly typeConstructor?: PslTypeConstructorCall;
|
|
63
65
|
readonly optional: boolean;
|
|
64
66
|
readonly list: boolean;
|
|
@@ -114,6 +116,11 @@ interface PslEnum {
|
|
|
114
116
|
readonly attributes: readonly PslAttribute[];
|
|
115
117
|
readonly span: PslSpan;
|
|
116
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* A reusable group of fields embedded in a model (a `type Name { … }` block) —
|
|
121
|
+
* e.g. a MongoDB embedded document or a Postgres composite type. Unlike
|
|
122
|
+
* {@link PslModel} it has no storage or identity of its own.
|
|
123
|
+
*/
|
|
117
124
|
interface PslCompositeType {
|
|
118
125
|
readonly kind: 'compositeType';
|
|
119
126
|
readonly name: string;
|
|
@@ -152,21 +159,43 @@ interface PslTypesBlock {
|
|
|
152
159
|
* (or whether) to map the PSL bucket to the IR sentinel.
|
|
153
160
|
*/
|
|
154
161
|
declare const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
|
|
162
|
+
/** A value in {@link PslNamespace.entries}: a built-in entity node or an extension-contributed {@link PslExtensionBlock}. */
|
|
163
|
+
type PslNamespaceEntry = PslModel | PslEnum | PslCompositeType | PslExtensionBlock;
|
|
155
164
|
/**
|
|
156
|
-
* A
|
|
157
|
-
* `
|
|
158
|
-
* `namespace { … }` block. Multiple `namespace foo { … }` blocks for the
|
|
159
|
-
* same name across one or more files reopen-merge into a single entry;
|
|
165
|
+
* A namespace block, or the parser's synthesised `__unspecified__` bucket for
|
|
166
|
+
* declarations outside any `namespace { … }`. Same-name blocks reopen-merge;
|
|
160
167
|
* `span` points at the first opening.
|
|
168
|
+
*
|
|
169
|
+
* Entities are stored canonically (ADR 224) in `entries[kind][name]`, where
|
|
170
|
+
* `kind` is the PSL keyword for built-ins or the block discriminator for
|
|
171
|
+
* extension kinds, e.g. `entries['policy_select']['ReadPosts']`.
|
|
161
172
|
*/
|
|
162
173
|
interface PslNamespace {
|
|
163
174
|
readonly kind: 'namespace';
|
|
164
175
|
readonly name: string;
|
|
176
|
+
/** Canonical store: a frozen container of frozen per-kind maps. The accessors below derive from it. */
|
|
177
|
+
readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;
|
|
178
|
+
/** Built-in models, from `entries['model']`. Extension kinds: {@link namespacePslExtensionBlocks}. */
|
|
165
179
|
readonly models: readonly PslModel[];
|
|
180
|
+
/** Built-in enums, from `entries['enum']`. */
|
|
166
181
|
readonly enums: readonly PslEnum[];
|
|
182
|
+
/** Built-in composite types, from `entries['compositeType']`. */
|
|
167
183
|
readonly compositeTypes: readonly PslCompositeType[];
|
|
168
184
|
readonly span: PslSpan;
|
|
169
185
|
}
|
|
186
|
+
/** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */
|
|
187
|
+
declare function makePslNamespace(init: {
|
|
188
|
+
readonly kind: 'namespace';
|
|
189
|
+
readonly name: string;
|
|
190
|
+
readonly entries: Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;
|
|
191
|
+
readonly span: PslSpan;
|
|
192
|
+
}): PslNamespace;
|
|
193
|
+
/**
|
|
194
|
+
* Builds the frozen `entries[kind][name]` container from per-kind arrays.
|
|
195
|
+
* Built-ins key on their PSL keyword; extension blocks key on their `kind`
|
|
196
|
+
* discriminator. Call this rather than hand-building the literal.
|
|
197
|
+
*/
|
|
198
|
+
declare function makePslNamespaceEntries(models: readonly PslModel[], enums: readonly PslEnum[], compositeTypes: readonly PslCompositeType[], extensionBlocks: readonly PslExtensionBlock[]): Readonly<Record<string, Readonly<Record<string, PslNamespaceEntry>>>>;
|
|
170
199
|
interface PslDocumentAst {
|
|
171
200
|
readonly kind: 'document';
|
|
172
201
|
readonly sourceId: string;
|
|
@@ -187,9 +216,52 @@ declare function flatPslEnums(ast: PslDocumentAst): readonly PslEnum[];
|
|
|
187
216
|
* Returns all composite types from every namespace in document order.
|
|
188
217
|
*/
|
|
189
218
|
declare function flatPslCompositeTypes(ast: PslDocumentAst): readonly PslCompositeType[];
|
|
219
|
+
/**
|
|
220
|
+
* The set of `entries` kind keys that the framework parser reserves for
|
|
221
|
+
* built-in PSL entity kinds. Any own-enumerable key on `PslNamespace.entries`
|
|
222
|
+
* that is **not** in this set was contributed by an extension-block descriptor.
|
|
223
|
+
*
|
|
224
|
+
* Built-in keys match the PSL keyword used on each block type:
|
|
225
|
+
* `'model'`, `'enum'`, `'compositeType'`.
|
|
226
|
+
*/
|
|
227
|
+
declare const BUILTIN_PSL_KIND_KEYS: ReadonlySet<string>;
|
|
228
|
+
/**
|
|
229
|
+
* Returns all extension-contributed blocks in the given namespace, in
|
|
230
|
+
* insertion order (the order the parser encountered them in the source).
|
|
231
|
+
*
|
|
232
|
+
* Reads from `namespace.entries`, skipping the three built-in kind keys
|
|
233
|
+
* (`'model'`, `'enum'`, `'compositeType'`). All remaining kind maps contain
|
|
234
|
+
* only `PslExtensionBlock` nodes by construction (see `makePslNamespaceEntries`).
|
|
235
|
+
*/
|
|
236
|
+
declare function namespacePslExtensionBlocks(ns: PslNamespace): readonly PslExtensionBlock[];
|
|
190
237
|
interface ParsePslDocumentInput {
|
|
191
238
|
readonly schema: string;
|
|
192
239
|
readonly sourceId: string;
|
|
240
|
+
/**
|
|
241
|
+
* Registry of declarative block descriptors, keyed by arbitrary path
|
|
242
|
+
* segments with {@link AuthoringPslBlockDescriptor} leaves. The registry
|
|
243
|
+
* teaches the parser which top-level keywords belong to extension
|
|
244
|
+
* contributions: when the parser encounters an unknown keyword, it looks
|
|
245
|
+
* it up here and, when found, reads the block generically into a
|
|
246
|
+
* {@link PslExtensionBlock} node. Absent or undefined means no extension
|
|
247
|
+
* blocks are registered and any unknown keyword yields
|
|
248
|
+
* `PSL_UNSUPPORTED_TOP_LEVEL_BLOCK`.
|
|
249
|
+
*
|
|
250
|
+
* Contrast with the parsed block nodes themselves, which live in
|
|
251
|
+
* {@link PslNamespace.entries} under their discriminator key (read them with
|
|
252
|
+
* {@link namespacePslExtensionBlocks}); this field holds the registry of
|
|
253
|
+
* descriptors that teach the parser how to read those blocks.
|
|
254
|
+
*/
|
|
255
|
+
readonly pslBlockDescriptors?: AuthoringPslBlockDescriptorNamespace;
|
|
256
|
+
/**
|
|
257
|
+
* Codec lookup for validating `value`-kind extension block parameters.
|
|
258
|
+
* When provided alongside `pslBlockDescriptors`, the generic validator runs
|
|
259
|
+
* over every parsed extension block after the full AST is assembled,
|
|
260
|
+
* appending any diagnostics to the parse result. Absent or undefined means
|
|
261
|
+
* no codec validation runs; `ref` resolution still runs when namespace
|
|
262
|
+
* context is available (built from the assembled namespaces).
|
|
263
|
+
*/
|
|
264
|
+
readonly codecLookup?: CodecLookup;
|
|
193
265
|
}
|
|
194
266
|
interface ParsePslDocumentResult {
|
|
195
267
|
readonly ast: PslDocumentAst;
|
|
@@ -197,5 +269,5 @@ interface ParsePslDocumentResult {
|
|
|
197
269
|
readonly ok: boolean;
|
|
198
270
|
}
|
|
199
271
|
//#endregion
|
|
200
|
-
export {
|
|
201
|
-
//# sourceMappingURL=psl-ast-
|
|
272
|
+
export { flatPslCompositeTypes as A, PslNamespace as C, PslTypesBlock as D, PslTypeConstructorCall as E, namespacePslExtensionBlocks as F, flatPslModels as M, makePslNamespace as N, PslUniqueConstraint as O, makePslNamespaceEntries as P, PslNamedTypeDeclaration as S, PslReferentialAction as T, PslField as _, PslAttributeArgument as a, PslModel as b, PslAttributeTarget as c, PslDefaultLiteralValue as d, PslDefaultValue as f, PslEnumValue as g, PslEnum as h, PslAttribute as i, flatPslEnums as j, UNSPECIFIED_PSL_NAMESPACE_ID as k, PslCompositeType as l, PslDocumentAst as m, ParsePslDocumentInput as n, PslAttributeNamedArgument as o, PslDiagnostic as p, ParsePslDocumentResult as r, PslAttributePositionalArgument as s, BUILTIN_PSL_KIND_KEYS as t, PslDefaultFunctionValue as u, PslFieldAttribute as v, PslNamespaceEntry as w, PslModelAttribute as x, PslIndexConstraint as y };
|
|
273
|
+
//# sourceMappingURL=psl-ast-Cn50B-UG.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"psl-ast-Cn50B-UG.d.mts","names":[],"sources":["../src/control/psl-ast.ts"],"mappings":"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"}
|
package/dist/psl-ast.d.mts
CHANGED
|
@@ -1,2 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { B as PslExtensionBlockParamOption, F as PslBlockParamRef, G as PslSpan, H as PslExtensionBlockParamScalarValue, I as PslBlockParamValue, L as PslDiagnosticCode, M as PslBlockParam, N as PslBlockParamList, P as PslBlockParamOption, R as PslExtensionBlock, U as PslExtensionBlockParamValue, V as PslExtensionBlockParamRef, W as PslPosition, m as AuthoringPslBlockDescriptorNamespace, p as AuthoringPslBlockDescriptor, z as PslExtensionBlockParamList } from "./framework-authoring-R0TYCkvG.mjs";
|
|
2
|
+
import { c as CodecLookup } from "./codec-DCQAerzB.mjs";
|
|
3
|
+
import { A as flatPslCompositeTypes, C as PslNamespace, D as PslTypesBlock, E as PslTypeConstructorCall, F as namespacePslExtensionBlocks, M as flatPslModels, N as makePslNamespace, O as PslUniqueConstraint, P as makePslNamespaceEntries, S as PslNamedTypeDeclaration, T as PslReferentialAction, _ as PslField, a as PslAttributeArgument, b as PslModel, c as PslAttributeTarget, d as PslDefaultLiteralValue, f as PslDefaultValue, g as PslEnumValue, h as PslEnum, i as PslAttribute, j as flatPslEnums, k as UNSPECIFIED_PSL_NAMESPACE_ID, l as PslCompositeType, m as PslDocumentAst, n as ParsePslDocumentInput, o as PslAttributeNamedArgument, p as PslDiagnostic, r as ParsePslDocumentResult, s as PslAttributePositionalArgument, t as BUILTIN_PSL_KIND_KEYS, u as PslDefaultFunctionValue, v as PslFieldAttribute, w as PslNamespaceEntry, x as PslModelAttribute, y as PslIndexConstraint } from "./psl-ast-Cn50B-UG.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/control/psl-extension-block-validator.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Context for ref resolution during extension-block validation.
|
|
8
|
+
*
|
|
9
|
+
* - `ownerNamespace` is the `PslNamespace` that contains the block being
|
|
10
|
+
* validated. Used for `same-namespace` scope checks.
|
|
11
|
+
* - `allNamespaces` is every namespace in the document. Used for `same-space`
|
|
12
|
+
* scope checks.
|
|
13
|
+
*/
|
|
14
|
+
interface ExtensionBlockRefResolutionContext {
|
|
15
|
+
readonly ownerNamespace: PslNamespace;
|
|
16
|
+
readonly allNamespaces: readonly PslNamespace[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validate a single parsed extension block against its descriptor.
|
|
20
|
+
*
|
|
21
|
+
* Returns an array of {@link PslDiagnostic} objects (possibly empty). The
|
|
22
|
+
* caller is responsible for threading `sourceId` into each returned diagnostic
|
|
23
|
+
* — the returned objects already have `sourceId` set from the `sourceId`
|
|
24
|
+
* parameter.
|
|
25
|
+
*
|
|
26
|
+
* @param node - The parsed block node produced by the generic framework parser.
|
|
27
|
+
* @param descriptor - The descriptor that claims this block's keyword.
|
|
28
|
+
* @param sourceId - The PSL source file identifier (threaded into diagnostics).
|
|
29
|
+
* @param codecLookup - Used to validate `value`-kind parameter literals via
|
|
30
|
+
* `codecLookup.get(codecId)?.decodeJson(JSON.parse(raw))`.
|
|
31
|
+
* @param refCtx - Namespace context for `ref`-kind scope resolution. Required
|
|
32
|
+
* when any descriptor parameter is `kind: 'ref'`; may be omitted if none are.
|
|
33
|
+
*/
|
|
34
|
+
declare function validateExtensionBlock(node: PslExtensionBlock, descriptor: AuthoringPslBlockDescriptor, sourceId: string, codecLookup: CodecLookup, refCtx?: ExtensionBlockRefResolutionContext): readonly PslDiagnostic[];
|
|
35
|
+
//#endregion
|
|
36
|
+
export { type AuthoringPslBlockDescriptorNamespace, BUILTIN_PSL_KIND_KEYS, type ExtensionBlockRefResolutionContext, ParsePslDocumentInput, ParsePslDocumentResult, PslAttribute, PslAttributeArgument, PslAttributeNamedArgument, PslAttributePositionalArgument, PslAttributeTarget, type PslBlockParam, type PslBlockParamList, type PslBlockParamOption, type PslBlockParamRef, type PslBlockParamValue, PslCompositeType, PslDefaultFunctionValue, PslDefaultLiteralValue, PslDefaultValue, PslDiagnostic, type PslDiagnosticCode, PslDocumentAst, PslEnum, PslEnumValue, type PslExtensionBlock, type PslExtensionBlockParamList, type PslExtensionBlockParamOption, type PslExtensionBlockParamRef, type PslExtensionBlockParamScalarValue, type PslExtensionBlockParamValue, PslField, PslFieldAttribute, PslIndexConstraint, PslModel, PslModelAttribute, PslNamedTypeDeclaration, PslNamespace, PslNamespaceEntry, type PslPosition, PslReferentialAction, type PslSpan, PslTypeConstructorCall, PslTypesBlock, PslUniqueConstraint, UNSPECIFIED_PSL_NAMESPACE_ID, flatPslCompositeTypes, flatPslEnums, flatPslModels, makePslNamespace, makePslNamespaceEntries, namespacePslExtensionBlocks, validateExtensionBlock };
|
|
37
|
+
//# sourceMappingURL=psl-ast.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"psl-ast.d.mts","names":[],"sources":["../src/control/psl-extension-block-validator.ts"],"mappings":";;;;;;;;;;;;;UA2EiB,kCAAA;EAAA,SACN,cAAA,EAAgB,YAAA;EAAA,SAChB,aAAA,WAAwB,YAAY;AAAA;;;;;;;;;;;;;;;;;iBAmB/B,sBAAA,CACd,IAAA,EAAM,iBAAA,EACN,UAAA,EAAY,2BAAA,EACZ,QAAA,UACA,WAAA,EAAa,WAAA,EACb,MAAA,GAAS,kCAAA,YACC,aAAA"}
|
package/dist/psl-ast.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { blindCast } from "@prisma-next/utils/casts";
|
|
1
2
|
//#region src/control/psl-ast.ts
|
|
2
3
|
/**
|
|
3
4
|
* Name of the synthesised namespace bucket the framework parser uses for
|
|
@@ -13,25 +14,242 @@
|
|
|
13
14
|
*/
|
|
14
15
|
const UNSPECIFIED_PSL_NAMESPACE_ID = "__unspecified__";
|
|
15
16
|
/**
|
|
17
|
+
* Stores `entries`; exposes `models`/`enums`/`compositeTypes` as getters over
|
|
18
|
+
* it. The getters are prototype members (non-enumerable), so spreading or
|
|
19
|
+
* `JSON.stringify`-ing a namespace copies only `entries`, never a duplicate view.
|
|
20
|
+
*/
|
|
21
|
+
var PslNamespaceNode = class {
|
|
22
|
+
kind = "namespace";
|
|
23
|
+
name;
|
|
24
|
+
entries;
|
|
25
|
+
span;
|
|
26
|
+
constructor(init) {
|
|
27
|
+
this.name = init.name;
|
|
28
|
+
this.entries = init.entries;
|
|
29
|
+
this.span = init.span;
|
|
30
|
+
Object.freeze(this);
|
|
31
|
+
}
|
|
32
|
+
get models() {
|
|
33
|
+
return blindCast(Object.values(this.entries["model"] ?? {}));
|
|
34
|
+
}
|
|
35
|
+
get enums() {
|
|
36
|
+
return blindCast(Object.values(this.entries["enum"] ?? {}));
|
|
37
|
+
}
|
|
38
|
+
get compositeTypes() {
|
|
39
|
+
return blindCast(Object.values(this.entries["compositeType"] ?? {}));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
/** Constructs a {@link PslNamespace}. Use this, never a namespace literal — the accessors must derive from `entries`. */
|
|
43
|
+
function makePslNamespace(init) {
|
|
44
|
+
return new PslNamespaceNode(init);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Builds the frozen `entries[kind][name]` container from per-kind arrays.
|
|
48
|
+
* Built-ins key on their PSL keyword; extension blocks key on their `kind`
|
|
49
|
+
* discriminator. Call this rather than hand-building the literal.
|
|
50
|
+
*/
|
|
51
|
+
function makePslNamespaceEntries(models, enums, compositeTypes, extensionBlocks) {
|
|
52
|
+
const container = {};
|
|
53
|
+
if (models.length > 0) {
|
|
54
|
+
const map = {};
|
|
55
|
+
for (const m of models) map[m.name] = m;
|
|
56
|
+
container["model"] = Object.freeze(map);
|
|
57
|
+
}
|
|
58
|
+
if (enums.length > 0) {
|
|
59
|
+
const map = {};
|
|
60
|
+
for (const e of enums) map[e.name] = e;
|
|
61
|
+
container["enum"] = Object.freeze(map);
|
|
62
|
+
}
|
|
63
|
+
if (compositeTypes.length > 0) {
|
|
64
|
+
const map = {};
|
|
65
|
+
for (const ct of compositeTypes) map[ct.name] = ct;
|
|
66
|
+
container["compositeType"] = Object.freeze(map);
|
|
67
|
+
}
|
|
68
|
+
for (const block of extensionBlocks) {
|
|
69
|
+
const existing = container[block.kind];
|
|
70
|
+
const newMap = existing ? blindCast({ ...existing }) : {};
|
|
71
|
+
newMap[block.name] = block;
|
|
72
|
+
container[block.kind] = Object.freeze(newMap);
|
|
73
|
+
}
|
|
74
|
+
return Object.freeze(container);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
16
77
|
* Returns all models from every namespace in document order. Convenience
|
|
17
78
|
* for consumers that don't (yet) need namespace-awareness.
|
|
18
79
|
*/
|
|
19
80
|
function flatPslModels(ast) {
|
|
20
|
-
return ast.namespaces.flatMap((ns) => ns.
|
|
81
|
+
return ast.namespaces.flatMap((ns) => blindCast(Object.values(ns.entries["model"] ?? {})));
|
|
21
82
|
}
|
|
22
83
|
/**
|
|
23
84
|
* Returns all enums from every namespace in document order.
|
|
24
85
|
*/
|
|
25
86
|
function flatPslEnums(ast) {
|
|
26
|
-
return ast.namespaces.flatMap((ns) => ns.
|
|
87
|
+
return ast.namespaces.flatMap((ns) => blindCast(Object.values(ns.entries["enum"] ?? {})));
|
|
27
88
|
}
|
|
28
89
|
/**
|
|
29
90
|
* Returns all composite types from every namespace in document order.
|
|
30
91
|
*/
|
|
31
92
|
function flatPslCompositeTypes(ast) {
|
|
32
|
-
return ast.namespaces.flatMap((ns) => ns.
|
|
93
|
+
return ast.namespaces.flatMap((ns) => blindCast(Object.values(ns.entries["compositeType"] ?? {})));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The set of `entries` kind keys that the framework parser reserves for
|
|
97
|
+
* built-in PSL entity kinds. Any own-enumerable key on `PslNamespace.entries`
|
|
98
|
+
* that is **not** in this set was contributed by an extension-block descriptor.
|
|
99
|
+
*
|
|
100
|
+
* Built-in keys match the PSL keyword used on each block type:
|
|
101
|
+
* `'model'`, `'enum'`, `'compositeType'`.
|
|
102
|
+
*/
|
|
103
|
+
const BUILTIN_PSL_KIND_KEYS = new Set([
|
|
104
|
+
"model",
|
|
105
|
+
"enum",
|
|
106
|
+
"compositeType"
|
|
107
|
+
]);
|
|
108
|
+
/**
|
|
109
|
+
* Returns all extension-contributed blocks in the given namespace, in
|
|
110
|
+
* insertion order (the order the parser encountered them in the source).
|
|
111
|
+
*
|
|
112
|
+
* Reads from `namespace.entries`, skipping the three built-in kind keys
|
|
113
|
+
* (`'model'`, `'enum'`, `'compositeType'`). All remaining kind maps contain
|
|
114
|
+
* only `PslExtensionBlock` nodes by construction (see `makePslNamespaceEntries`).
|
|
115
|
+
*/
|
|
116
|
+
function namespacePslExtensionBlocks(ns) {
|
|
117
|
+
const result = [];
|
|
118
|
+
for (const [kindKey, kindMap] of Object.entries(ns.entries)) {
|
|
119
|
+
if (BUILTIN_PSL_KIND_KEYS.has(kindKey)) continue;
|
|
120
|
+
for (const entry of Object.values(kindMap)) result.push(blindCast(entry));
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/control/psl-extension-block-validator.ts
|
|
126
|
+
/**
|
|
127
|
+
* Validate a single parsed extension block against its descriptor.
|
|
128
|
+
*
|
|
129
|
+
* Returns an array of {@link PslDiagnostic} objects (possibly empty). The
|
|
130
|
+
* caller is responsible for threading `sourceId` into each returned diagnostic
|
|
131
|
+
* — the returned objects already have `sourceId` set from the `sourceId`
|
|
132
|
+
* parameter.
|
|
133
|
+
*
|
|
134
|
+
* @param node - The parsed block node produced by the generic framework parser.
|
|
135
|
+
* @param descriptor - The descriptor that claims this block's keyword.
|
|
136
|
+
* @param sourceId - The PSL source file identifier (threaded into diagnostics).
|
|
137
|
+
* @param codecLookup - Used to validate `value`-kind parameter literals via
|
|
138
|
+
* `codecLookup.get(codecId)?.decodeJson(JSON.parse(raw))`.
|
|
139
|
+
* @param refCtx - Namespace context for `ref`-kind scope resolution. Required
|
|
140
|
+
* when any descriptor parameter is `kind: 'ref'`; may be omitted if none are.
|
|
141
|
+
*/
|
|
142
|
+
function validateExtensionBlock(node, descriptor, sourceId, codecLookup, refCtx) {
|
|
143
|
+
const diagnostics = [];
|
|
144
|
+
const descriptorKeys = new Set(Object.keys(descriptor.parameters));
|
|
145
|
+
const nodeKeys = new Set(Object.keys(node.parameters));
|
|
146
|
+
for (const key of nodeKeys) if (!descriptorKeys.has(key)) {
|
|
147
|
+
const captured = node.parameters[key];
|
|
148
|
+
diagnostics.push({
|
|
149
|
+
code: "PSL_EXTENSION_UNKNOWN_PARAMETER",
|
|
150
|
+
message: `Unknown parameter "${key}" in "${descriptor.keyword}" block "${node.name}". The descriptor does not declare this parameter.`,
|
|
151
|
+
sourceId,
|
|
152
|
+
span: captured?.span ?? node.span
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
for (const [key, param] of Object.entries(descriptor.parameters)) if (param.required === true && !nodeKeys.has(key)) diagnostics.push({
|
|
156
|
+
code: "PSL_EXTENSION_MISSING_REQUIRED_PARAMETER",
|
|
157
|
+
message: `Required parameter "${key}" is missing from "${descriptor.keyword}" block "${node.name}".`,
|
|
158
|
+
sourceId,
|
|
159
|
+
span: node.span
|
|
160
|
+
});
|
|
161
|
+
for (const [key, param] of Object.entries(descriptor.parameters)) {
|
|
162
|
+
const captured = node.parameters[key];
|
|
163
|
+
if (captured === void 0) continue;
|
|
164
|
+
validateParam(node, descriptor, key, param, captured, sourceId, codecLookup, refCtx, diagnostics);
|
|
165
|
+
}
|
|
166
|
+
return diagnostics;
|
|
167
|
+
}
|
|
168
|
+
function validateParam(node, descriptor, key, param, captured, sourceId, codecLookup, refCtx, diagnostics) {
|
|
169
|
+
switch (param.kind) {
|
|
170
|
+
case "option":
|
|
171
|
+
if (captured.kind !== "option") return;
|
|
172
|
+
if (!param.values.includes(captured.token)) diagnostics.push({
|
|
173
|
+
code: "PSL_EXTENSION_OPTION_OUT_OF_SET",
|
|
174
|
+
message: `Parameter "${key}" in "${descriptor.keyword}" block "${node.name}" has value "${captured.token}" which is not one of the allowed values: ${param.values.map((v) => `"${v}"`).join(", ")}.`,
|
|
175
|
+
sourceId,
|
|
176
|
+
span: captured.span
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
case "value": {
|
|
180
|
+
if (captured.kind !== "value") return;
|
|
181
|
+
const codec = codecLookup.get(param.codecId);
|
|
182
|
+
if (codec === void 0) {
|
|
183
|
+
diagnostics.push({
|
|
184
|
+
code: "PSL_EXTENSION_INVALID_VALUE",
|
|
185
|
+
message: `Parameter "${key}" in "${descriptor.keyword}" block "${node.name}" references unknown codec "${param.codecId}".`,
|
|
186
|
+
sourceId,
|
|
187
|
+
span: captured.span
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
let jsonValue;
|
|
192
|
+
try {
|
|
193
|
+
jsonValue = JSON.parse(captured.raw);
|
|
194
|
+
} catch {
|
|
195
|
+
diagnostics.push({
|
|
196
|
+
code: "PSL_EXTENSION_INVALID_VALUE",
|
|
197
|
+
message: `Parameter "${key}" in "${descriptor.keyword}" block "${node.name}" is not a valid JSON literal (expected a JSON string, number, boolean, or null): ${captured.raw}`,
|
|
198
|
+
sourceId,
|
|
199
|
+
span: captured.span
|
|
200
|
+
});
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
codec.decodeJson(blindCast(jsonValue));
|
|
205
|
+
} catch (err) {
|
|
206
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
207
|
+
diagnostics.push({
|
|
208
|
+
code: "PSL_EXTENSION_INVALID_VALUE",
|
|
209
|
+
message: `Parameter "${key}" in "${descriptor.keyword}" block "${node.name}" was rejected by codec "${param.codecId}": ${reason}`,
|
|
210
|
+
sourceId,
|
|
211
|
+
span: captured.span
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
case "ref":
|
|
217
|
+
if (captured.kind !== "ref") return;
|
|
218
|
+
validateRef(node, descriptor, key, param, captured.identifier, captured.span, sourceId, refCtx, diagnostics);
|
|
219
|
+
return;
|
|
220
|
+
case "list":
|
|
221
|
+
if (captured.kind !== "list") return;
|
|
222
|
+
for (const item of captured.items) validateParam(node, descriptor, key, param.of, item, sourceId, codecLookup, refCtx, diagnostics);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function validateRef(node, descriptor, key, param, identifier, span, sourceId, refCtx, diagnostics) {
|
|
227
|
+
if (param.scope === "cross-space") return;
|
|
228
|
+
if (refCtx === void 0) return;
|
|
229
|
+
const namespacesToSearch = param.scope === "same-namespace" ? [refCtx.ownerNamespace] : refCtx.allNamespaces;
|
|
230
|
+
if (!resolveEntityInNamespaces(identifier, param.refKind, namespacesToSearch)) {
|
|
231
|
+
const scopeLabel = param.scope === "same-namespace" ? "the same namespace" : "any namespace in the schema";
|
|
232
|
+
diagnostics.push({
|
|
233
|
+
code: "PSL_EXTENSION_UNRESOLVED_REF",
|
|
234
|
+
message: `Parameter "${key}" in "${descriptor.keyword}" block "${node.name}" refers to "${identifier}" (expected ${param.refKind}), but no entity with that name and kind was found in ${scopeLabel}.`,
|
|
235
|
+
sourceId,
|
|
236
|
+
span
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* True if an entity named `name` of kind `refKind` exists in any of the given
|
|
242
|
+
* namespaces. Built-in and extension kinds resolve the same way, through
|
|
243
|
+
* `entries[refKind]`.
|
|
244
|
+
*/
|
|
245
|
+
function resolveEntityInNamespaces(name, refKind, namespaces) {
|
|
246
|
+
for (const ns of namespaces) {
|
|
247
|
+
const kindMap = ns.entries[refKind];
|
|
248
|
+
if (kindMap !== void 0 && Object.hasOwn(kindMap, name)) return true;
|
|
249
|
+
}
|
|
250
|
+
return false;
|
|
33
251
|
}
|
|
34
252
|
//#endregion
|
|
35
|
-
export { UNSPECIFIED_PSL_NAMESPACE_ID, flatPslCompositeTypes, flatPslEnums, flatPslModels };
|
|
253
|
+
export { BUILTIN_PSL_KIND_KEYS, UNSPECIFIED_PSL_NAMESPACE_ID, flatPslCompositeTypes, flatPslEnums, flatPslModels, makePslNamespace, makePslNamespaceEntries, namespacePslExtensionBlocks, validateExtensionBlock };
|
|
36
254
|
|
|
37
255
|
//# sourceMappingURL=psl-ast.mjs.map
|