Skip to content

Commit d78acfd

Browse files
committed
feat: add monorepo's entry
1 parent 1b05fec commit d78acfd

File tree

2 files changed

+95
-9
lines changed

2 files changed

+95
-9
lines changed

packages/schema/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
"type": "boolean",
7070
"default": true,
7171
"description": "Search for Mermaid extensions when viewing Mermaid source."
72+
},
73+
"zmodel.entries": {
74+
"type": "array",
75+
"items": { "type": "string" },
76+
"default": [],
77+
"description": "Glob patterns for entry .zmodel files. When set, the language server will only treat matched files as entry schemas (e.g. [\"**/dbs/db1/schema.zmodel\",\"**/dbs/db2/schema.zmodel\"])."
7278
}
7379
}
7480
},

packages/schema/src/language-server/zmodel-workspace-manager.ts

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,82 @@
11
import { isPlugin, Model } from '@zenstackhq/language/ast';
22
import { getLiteral } from '@zenstackhq/sdk';
3-
import { DefaultWorkspaceManager, interruptAndCheck, LangiumDocument } from 'langium';
3+
import {
4+
ConfigurationProvider,
5+
DefaultWorkspaceManager,
6+
interruptAndCheck,
7+
LangiumDocument,
8+
LangiumSharedServices,
9+
} from 'langium';
410
import fs from 'fs';
511
import path from 'path';
612
import { CancellationToken, WorkspaceFolder } from 'vscode-languageserver';
713
import { URI, Utils } from 'vscode-uri';
814
import { PLUGIN_MODULE_NAME, STD_LIB_MODULE_NAME } from './constants';
15+
import { ZModelLanguageMetaData } from '@zenstackhq/language/generated/module';
916

1017
/**
1118
* Custom Langium WorkspaceManager implementation which automatically loads stdlib.zmodel
1219
*/
1320
export class ZModelWorkspaceManager extends DefaultWorkspaceManager {
21+
protected readonly configurationProvider: ConfigurationProvider;
22+
23+
constructor(services: LangiumSharedServices) {
24+
super(services);
25+
26+
this.configurationProvider = services.workspace.ConfigurationProvider;
27+
}
1428
public pluginModels = new Set<string>();
29+
private entryDocumentUris: Set<string> = new Set();
30+
31+
public isEntryDocument(uri: string | URI): boolean {
32+
const u = typeof uri === 'string' ? uri : uri.toString();
33+
return this.entryDocumentUris.has(u);
34+
}
35+
36+
public getEntryDocumentUris(): Set<string> {
37+
return new Set(this.entryDocumentUris);
38+
}
1539

1640
protected async loadAdditionalDocuments(
1741
_folders: WorkspaceFolder[],
1842
_collector: (document: LangiumDocument) => void
1943
): Promise<void> {
2044
await super.loadAdditionalDocuments(_folders, _collector);
21-
22-
let stdLibPath: string;
45+
46+
let stdLibPath: string;
2347
// First, try to find the stdlib from an installed zenstack package
2448
// in the project's node_modules
2549
let installedStdlibPath: string | undefined;
2650
for (const folder of _folders) {
2751
const folderPath = this.getRootFolder(folder).fsPath;
2852
try {
2953
// Try to resolve zenstack from the workspace folder
30-
const languagePackagePath = require.resolve('zenstack/package.json', {
31-
paths: [folderPath]
54+
const languagePackagePath = require.resolve('zenstack/package.json', {
55+
paths: [folderPath],
3256
});
3357
const languagePackageDir = path.dirname(languagePackagePath);
3458
const candidateStdlibPath = path.join(languagePackageDir, 'res', STD_LIB_MODULE_NAME);
35-
59+
3660
// Check if the stdlib file exists in the installed package
3761
if (fs.existsSync(candidateStdlibPath)) {
3862
installedStdlibPath = candidateStdlibPath;
3963
console.log(`Found installed zenstack package stdlib at ${installedStdlibPath}`);
4064
break;
41-
}
65+
}
4266
} catch (error) {
4367
// Package not found or other error, continue to next folder
4468
continue;
4569
}
4670
}
47-
71+
4872
if (installedStdlibPath) {
4973
stdLibPath = installedStdlibPath;
5074
} else {
5175
// Fallback to bundled stdlib
5276
stdLibPath = path.join(__dirname, '../res', STD_LIB_MODULE_NAME);
5377
console.log(`Using bundled stdlib in extension`);
5478
}
55-
79+
5680
const stdLibUri = URI.file(stdLibPath);
5781
console.log(`Adding stdlib document from ${stdLibUri}`);
5882
const stdlib = this.langiumDocuments.getOrCreateDocument(stdLibUri);
@@ -112,6 +136,62 @@ export class ZModelWorkspaceManager extends DefaultWorkspaceManager {
112136
}
113137
}
114138

139+
// Save entry document URIs based on user configuration (simple mode: accept absolute file paths or file:// URIs)
140+
try {
141+
const entries = await this.configurationProvider.getConfiguration(
142+
ZModelLanguageMetaData.languageId,
143+
'entries'
144+
);
145+
const entryUris = new Set<string>();
146+
if (Array.isArray(entries)) {
147+
for (const e of entries) {
148+
if (typeof e !== 'string') continue;
149+
try {
150+
if (e.startsWith('file://')) {
151+
const u = URI.parse(e);
152+
entryUris.add(u.toString());
153+
} else if (path.isAbsolute(e)) {
154+
const u = URI.file(e);
155+
entryUris.add(u.toString());
156+
} else {
157+
// Try resolving relative entries against workspace folders
158+
let resolved = false;
159+
for (const wf of folders) {
160+
try {
161+
const folderPath = this.getRootFolder(wf).fsPath;
162+
const candidate = path.join(folderPath, e);
163+
if (fs.existsSync(candidate)) {
164+
const u = URI.file(candidate);
165+
entryUris.add(u.toString());
166+
resolved = true;
167+
break;
168+
}
169+
} catch {
170+
// ignore and continue with other folders
171+
}
172+
}
173+
if (!resolved) {
174+
// ignore relative/glob entries that cannot be resolved in simple mode
175+
console.warn(
176+
`zmodel.entries value ignored (not absolute/file URI/resolvable relative to workspace): ${e}`
177+
);
178+
}
179+
}
180+
} catch {
181+
console.warn(`Invalid zmodel.entries entry ignored: ${e}`);
182+
}
183+
}
184+
}
185+
this.entryDocumentUris = entryUris;
186+
if (this.entryDocumentUris.size > 0) {
187+
console.log(
188+
`ZModelWorkspaceManager: using configured zmodel.entries: ${Array.from(this.entryDocumentUris)}`
189+
);
190+
}
191+
} catch (err) {
192+
console.warn('Failed to read zmodel.entries configuration:', err);
193+
}
194+
115195
// Only after creating all documents do we check whether we need to cancel the initialization
116196
// The document builder will later pick up on all unprocessed documents
117197
await interruptAndCheck(cancelToken);

0 commit comments

Comments
 (0)