From 89dbefef94472c5b54e709d6af26991787a2fe82 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:07:53 +0800 Subject: [PATCH] fix: Zmodel linker doesn't recursively visit base types when building resolution scopes --- .../src/language-server/zmodel-linker.ts | 15 ++++++++---- .../tests/regression/issue-971.test.ts | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 tests/integration/tests/regression/issue-971.test.ts diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts index ef97cf4b6..69fdf67c2 100644 --- a/packages/schema/src/language-server/zmodel-linker.ts +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -519,12 +519,17 @@ export class ZModelLinker extends DefaultLinker { private resolveDataModel(node: DataModel, document: LangiumDocument, extraScopes: ScopeProvider[]) { if (node.superTypes.length > 0) { - const providers = node.superTypes.map( - (superType) => (name: string) => superType.ref?.fields.find((f) => f.name === name) - ); - extraScopes = [...providers, ...extraScopes]; + const superTypeProviders: ScopeProvider[] = []; + // build scope providers for super types recursively with breadth-first search + const queue = node.superTypes.map((t) => t.ref!); + while (queue.length > 0) { + const superType = queue.shift()!; + const provider = (name: string) => superType.fields.find((f) => f.name === name); + superTypeProviders.push(provider); + queue.push(...superType.superTypes.map((t) => t.ref!)); + } + extraScopes = [...superTypeProviders, ...extraScopes]; } - return this.resolveDefault(node, document, extraScopes); } diff --git a/tests/integration/tests/regression/issue-971.test.ts b/tests/integration/tests/regression/issue-971.test.ts new file mode 100644 index 000000000..40990aa6a --- /dev/null +++ b/tests/integration/tests/regression/issue-971.test.ts @@ -0,0 +1,23 @@ +import { loadSchema } from '@zenstackhq/testtools'; + +describe('Regression: issue 971', () => { + it('regression', async () => { + await loadSchema( + ` + abstract model Level1 { + id String @id @default(cuid()) + URL String? + @@validate(URL != null, "URL must be provided") // works + } + abstract model Level2 extends Level1 { + @@validate(URL != null, "URL must be provided") // works + } + abstract model Level3 extends Level2 { + @@validate(URL != null, "URL must be provided") // doesn't work + } + model Foo extends Level3 { + } + ` + ); + }); +});