Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/schema/src/language-server/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { DataModel, DataModelField, isArrayExpr, isReferenceExpr, ReferenceExpr } from '@zenstackhq/language/ast';
import {
isArrayExpr,
isReferenceExpr,
type DataModel,
type DataModelField,
type ReferenceExpr,
} from '@zenstackhq/language/ast';
import { resolved } from '@zenstackhq/sdk';

/**
Expand Down
31 changes: 14 additions & 17 deletions packages/schema/src/language-server/zmodel-linker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@ import {
isReferenceExpr,
isStringLiteral,
} from '@zenstackhq/language/ast';
import {
getAuthModel,
getContainingModel,
getModelFieldsWithBases,
isAuthInvocation,
isFutureExpr,
} from '@zenstackhq/sdk';
import { getAuthModel, getModelFieldsWithBases, isAuthInvocation, isFutureExpr } from '@zenstackhq/sdk';
import {
AstNode,
AstNodeDescription,
Expand All @@ -52,13 +46,14 @@ import {
LangiumServices,
LinkingError,
Reference,
getContainerOfType,
interruptAndCheck,
isReference,
streamContents,
} from 'langium';
import { match } from 'ts-pattern';
import { CancellationToken } from 'vscode-jsonrpc';
import { getAllDataModelsIncludingImports, getContainingDataModel } from '../utils/ast-utils';
import { getAllLoadedAndReachableDataModels, getContainingDataModel } from '../utils/ast-utils';
import { mapBuiltinTypeToExpressionType } from './validator/utils';

interface DefaultReference extends Reference {
Expand Down Expand Up @@ -283,15 +278,17 @@ export class ZModelLinker extends DefaultLinker {
// eslint-disable-next-line @typescript-eslint/ban-types
const funcDecl = node.function.ref as FunctionDecl;
if (isAuthInvocation(node)) {
// auth() function is resolved to User model in the current document
const model = getContainingModel(node);

if (model) {
const allDataModels = getAllDataModelsIncludingImports(this.langiumDocuments(), model);
const authModel = getAuthModel(allDataModels);
if (authModel) {
node.$resolvedType = { decl: authModel, nullable: true };
}
// auth() function is resolved against all loaded and reachable documents

// get all data models from loaded and reachable documents
const allDataModels = getAllLoadedAndReachableDataModels(
this.langiumDocuments(),
getContainerOfType(node, isDataModel)
);

const authModel = getAuthModel(allDataModels);
if (authModel) {
node.$resolvedType = { decl: authModel, nullable: true };
}
} else if (isFutureExpr(node)) {
// future() function is resolved to current model
Expand Down
24 changes: 12 additions & 12 deletions packages/schema/src/language-server/zmodel-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
import { match } from 'ts-pattern';
import { CancellationToken } from 'vscode-jsonrpc';
import {
getAllDataModelsIncludingImports,
getAllLoadedAndReachableDataModels,
isCollectionPredicate,
isFutureInvocation,
resolveImportUri,
Expand Down Expand Up @@ -219,18 +219,18 @@ export class ZModelScopeProvider extends DefaultScopeProvider {
}

private createScopeForAuthModel(node: AstNode, globalScope: Scope) {
const model = getContainerOfType(node, isModel);
if (model) {
const allDataModels = getAllDataModelsIncludingImports(
this.services.shared.workspace.LangiumDocuments,
model
);
const authModel = getAuthModel(allDataModels);
if (authModel) {
return this.createScopeForModel(authModel, globalScope);
}
// get all data models from loaded and reachable documents
const allDataModels = getAllLoadedAndReachableDataModels(
this.services.shared.workspace.LangiumDocuments,
getContainerOfType(node, isDataModel)
);

const authModel = getAuthModel(allDataModels);
if (authModel) {
return this.createScopeForModel(authModel, globalScope);
} else {
return EMPTY_SCOPE;
}
return EMPTY_SCOPE;
}
}

Expand Down
33 changes: 33 additions & 0 deletions packages/schema/src/utils/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,36 @@ export function findUpAst(node: AstNode, predicate: (node: AstNode) => boolean):
}
return undefined;
}

/**
* Gets all data models from all loaded documents
*/
export function getAllLoadedDataModels(langiumDocuments: LangiumDocuments) {
return langiumDocuments.all
.map((doc) => doc.parseResult.value as Model)
.flatMap((model) => model.declarations.filter(isDataModel))
.toArray();
}

/**
* Gets all data models from loaded and reachable documents
*/
export function getAllLoadedAndReachableDataModels(langiumDocuments: LangiumDocuments, fromModel?: DataModel) {
// get all data models from loaded documents
const allDataModels = getAllLoadedDataModels(langiumDocuments);

if (fromModel) {
// merge data models transitively reached from the current model
const model = getContainerOfType(fromModel, isModel);
if (model) {
const transitiveDataModels = getAllDataModelsIncludingImports(langiumDocuments, model);
transitiveDataModels.forEach((dm) => {
if (!allDataModels.includes(dm)) {
allDataModels.push(dm);
}
});
}
}

return allDataModels;
}
26 changes: 26 additions & 0 deletions tests/regression/tests/issue-1388.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { FILE_SPLITTER, loadSchema } from '@zenstackhq/testtools';

describe('issue 1388', () => {
it('regression', async () => {
await loadSchema(
`schema.zmodel
import './auth'
import './post'

${FILE_SPLITTER}auth.zmodel
model User {
id String @id @default(cuid())
role String
}

${FILE_SPLITTER}post.zmodel
model Post {
id String @id @default(nanoid(6))
title String
@@deny('all', auth() == null)
@@allow('all', auth().id == 'user1')
}
`
);
});
});