UNPKG

zenstack

Version:

FullStack enhancement for Prisma ORM: seamless integration from database to UI

218 lines 11 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZModelScopeProvider = exports.ZModelScopeComputation = void 0; const ast_1 = require("@zenstackhq/language/ast"); const sdk_1 = require("@zenstackhq/sdk"); const langium_1 = require("langium"); const ts_pattern_1 = require("ts-pattern"); const ast_utils_1 = require("../utils/ast-utils"); const constants_1 = require("./constants"); const utils_1 = require("./validator/utils"); /** * Custom Langium ScopeComputation implementation which adds enum fields into global scope */ class ZModelScopeComputation extends langium_1.DefaultScopeComputation { constructor(services) { super(services); this.services = services; } computeExports(document, cancelToken) { const _super = Object.create(null, { computeExports: { get: () => super.computeExports } }); return __awaiter(this, void 0, void 0, function* () { const result = yield _super.computeExports.call(this, document, cancelToken); // add enum fields so they can be globally resolved across modules for (const node of (0, langium_1.streamAllContents)(document.parseResult.value)) { if (cancelToken) { yield (0, langium_1.interruptAndCheck)(cancelToken); } if ((0, ast_1.isEnumField)(node)) { const desc = this.services.workspace.AstNodeDescriptionProvider.createDescription(node, node.name, document); result.push(desc); } } return result; }); } processNode(node, document, scopes) { super.processNode(node, document, scopes); if ((0, ast_1.isDataModel)(node) && !node.$baseMerged) { // add base fields to the scope recursively const bases = (0, sdk_1.getRecursiveBases)(node); for (const base of bases) { for (const field of base.fields) { scopes.add(node, this.descriptions.createDescription(field, this.nameProvider.getName(field))); } } } } } exports.ZModelScopeComputation = ZModelScopeComputation; class ZModelScopeProvider extends langium_1.DefaultScopeProvider { constructor(services) { super(services); this.services = services; } getGlobalScope(referenceType, context) { const model = (0, langium_1.getContainerOfType)(context.container, ast_1.isModel); if (!model) { return langium_1.EMPTY_SCOPE; } const importedUris = (0, langium_1.stream)(model.imports).map(ast_utils_1.resolveImportUri).nonNullable(); const importedElements = this.indexManager.allElements(referenceType).filter((des) => { var _a; // allow current document return (0, langium_1.equalURI)(des.documentUri, (_a = model.$document) === null || _a === void 0 ? void 0 : _a.uri) || // allow stdlib des.documentUri.path.endsWith(constants_1.STD_LIB_MODULE_NAME) || // allow plugin models des.documentUri.path.endsWith(constants_1.PLUGIN_MODULE_NAME) || // allow imported documents importedUris.some((importedUri) => (0, langium_1.equalURI)(des.documentUri, importedUri)); }); return new langium_1.StreamScope(importedElements); } getScope(context) { if ((0, ast_1.isMemberAccessExpr)(context.container) && context.container.operand && context.property === 'member') { return this.getMemberAccessScope(context); } if ((0, ast_1.isReferenceExpr)(context.container) && context.property === 'target') { // when reference expression is resolved inside a collection predicate, the scope is the collection const containerCollectionPredicate = getCollectionPredicateContext(context.container); if (containerCollectionPredicate) { return this.getCollectionPredicateScope(context, containerCollectionPredicate); } } return super.getScope(context); } getMemberAccessScope(context) { const referenceType = this.reflection.getReferenceType(context); const globalScope = this.getGlobalScope(referenceType, context); const node = context.container; // typedef's fields are only added to the scope if the access starts with `auth().` // or the member access resides inside a typedef const allowTypeDefScope = (0, utils_1.isAuthOrAuthMemberAccess)(node.operand) || !!(0, langium_1.getContainerOfType)(node, ast_1.isTypeDef); return (0, ts_pattern_1.match)(node.operand) .when(ast_1.isReferenceExpr, (operand) => { var _a; // operand is a reference, it can only be a model/type-def field const ref = operand.target.ref; if ((0, ast_1.isDataModelField)(ref) || (0, ast_1.isTypeDefField)(ref)) { return this.createScopeForContainer((_a = ref.type.reference) === null || _a === void 0 ? void 0 : _a.ref, globalScope, allowTypeDefScope); } return langium_1.EMPTY_SCOPE; }) .when(ast_1.isMemberAccessExpr, (operand) => { var _a, _b; // operand is a member access, it must be resolved to a non-array model/typedef type const ref = operand.member.ref; if ((0, ast_1.isDataModelField)(ref) && !ref.type.array) { return this.createScopeForContainer((_a = ref.type.reference) === null || _a === void 0 ? void 0 : _a.ref, globalScope, allowTypeDefScope); } if ((0, ast_1.isTypeDefField)(ref) && !ref.type.array) { return this.createScopeForContainer((_b = ref.type.reference) === null || _b === void 0 ? void 0 : _b.ref, globalScope, allowTypeDefScope); } return langium_1.EMPTY_SCOPE; }) .when(ast_1.isThisExpr, () => { // operand is `this`, resolve to the containing model return this.createScopeForContainingModel(node, globalScope); }) .when(ast_1.isInvocationExpr, (operand) => { // deal with member access from `auth()` and `future() if ((0, sdk_1.isAuthInvocation)(operand)) { // resolve to `User` or `@@auth` decl return this.createScopeForAuth(node, globalScope); } if ((0, ast_utils_1.isFutureInvocation)(operand)) { // resolve `future()` to the containing model return this.createScopeForContainingModel(node, globalScope); } return langium_1.EMPTY_SCOPE; }) .otherwise(() => langium_1.EMPTY_SCOPE); } getCollectionPredicateScope(context, collectionPredicate) { const referenceType = this.reflection.getReferenceType(context); const globalScope = this.getGlobalScope(referenceType, context); const collection = collectionPredicate.left; // typedef's fields are only added to the scope if the access starts with `auth().` const allowTypeDefScope = (0, utils_1.isAuthOrAuthMemberAccess)(collection); return (0, ts_pattern_1.match)(collection) .when(ast_1.isReferenceExpr, (expr) => { var _a; // collection is a reference - model or typedef field const ref = expr.target.ref; if ((0, ast_1.isDataModelField)(ref) || (0, ast_1.isTypeDefField)(ref)) { return this.createScopeForContainer((_a = ref.type.reference) === null || _a === void 0 ? void 0 : _a.ref, globalScope, allowTypeDefScope); } return langium_1.EMPTY_SCOPE; }) .when(ast_1.isMemberAccessExpr, (expr) => { var _a; // collection is a member access, it can only be resolved to a model or typedef field const ref = expr.member.ref; if ((0, ast_1.isDataModelField)(ref) || (0, ast_1.isTypeDefField)(ref)) { return this.createScopeForContainer((_a = ref.type.reference) === null || _a === void 0 ? void 0 : _a.ref, globalScope, allowTypeDefScope); } return langium_1.EMPTY_SCOPE; }) .when(sdk_1.isAuthInvocation, (expr) => { return this.createScopeForAuth(expr, globalScope); }) .otherwise(() => langium_1.EMPTY_SCOPE); } createScopeForContainingModel(node, globalScope) { const model = (0, langium_1.getContainerOfType)(node, ast_1.isDataModel); if (model) { return this.createScopeForContainer(model, globalScope); } else { return langium_1.EMPTY_SCOPE; } } createScopeForContainer(node, globalScope, includeTypeDefScope = false) { if ((0, ast_1.isDataModel)(node)) { return this.createScopeForNodes((0, sdk_1.getModelFieldsWithBases)(node), globalScope); } else if (includeTypeDefScope && (0, ast_1.isTypeDef)(node)) { return this.createScopeForNodes(node.fields, globalScope); } else { return langium_1.EMPTY_SCOPE; } } createScopeForAuth(node, globalScope) { // get all data models and type defs from loaded and reachable documents const decls = (0, ast_utils_1.getAllLoadedAndReachableDataModelsAndTypeDefs)(this.services.shared.workspace.LangiumDocuments, (0, langium_1.getContainerOfType)(node, ast_1.isDataModel)); const authDecl = (0, sdk_1.getAuthDecl)(decls); if (authDecl) { return this.createScopeForContainer(authDecl, globalScope, true); } else { return langium_1.EMPTY_SCOPE; } } } exports.ZModelScopeProvider = ZModelScopeProvider; function getCollectionPredicateContext(node) { let curr = node; while (curr) { if (curr.$container && (0, ast_utils_1.isCollectionPredicate)(curr.$container) && curr.$containerProperty === 'right') { return curr.$container; } curr = curr.$container; } return undefined; } //# sourceMappingURL=zmodel-scope.js.map