@likec4/language-server 1.43.0 → 1.44.0
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/browser/package.json +1 -1
- package/browser-worker/package.json +1 -1
- package/dist/LikeC4LanguageServices.d.ts +12 -19
- package/dist/LikeC4LanguageServices.js +182 -0
- package/dist/Rpc.js +245 -0
- package/dist/ast.d.ts +5 -1
- package/dist/ast.js +253 -0
- package/dist/browser-worker.js +4 -0
- package/dist/browser.js +35 -0
- package/dist/bundled.js +42 -0
- package/dist/bundled.mjs +3542 -3896
- package/dist/documentation/documentation-provider.js +51 -0
- package/dist/documentation/index.js +1 -0
- package/dist/empty.js +2 -0
- package/dist/filesystem/ChokidarWatcher.js +97 -0
- package/dist/filesystem/FileSystemWatcher.js +14 -0
- package/dist/filesystem/LikeC4FileSystem.d.ts +1 -2
- package/dist/filesystem/LikeC4FileSystem.js +126 -0
- package/dist/filesystem/index.d.ts +26 -0
- package/dist/filesystem/index.js +29 -0
- package/dist/formatting/LikeC4Formatter.js +637 -0
- package/dist/formatting/utils.js +18 -0
- package/dist/generated/ast.js +2155 -0
- package/dist/generated/{grammar.mjs → grammar.js} +6 -2
- package/dist/generated/module.d.ts +6 -1
- package/dist/generated/module.js +27 -0
- package/dist/generated-lib/{icons.mjs → icons.js} +11 -7
- package/dist/index.d.ts +7 -0
- package/dist/index.js +53 -0
- package/dist/{likec4lib.mjs → likec4lib.js} +3 -3
- package/dist/logger.js +81 -0
- package/dist/lsp/CodeActionProvider.d.ts +14 -0
- package/dist/lsp/CodeActionProvider.js +33 -0
- package/dist/lsp/CodeLensProvider.js +44 -0
- package/dist/lsp/CompletionProvider.d.ts +3 -1
- package/dist/lsp/CompletionProvider.js +200 -0
- package/dist/lsp/DocumentHighlightProvider.js +10 -0
- package/dist/lsp/DocumentLinkProvider.js +58 -0
- package/dist/lsp/DocumentSymbolProvider.js +306 -0
- package/dist/lsp/HoverProvider.js +106 -0
- package/dist/lsp/RenameProvider.js +6 -0
- package/dist/lsp/SemanticTokenProvider.js +257 -0
- package/dist/lsp/index.d.ts +1 -0
- package/dist/lsp/index.js +9 -0
- package/dist/mcp/MCPServerFactory.js +73 -0
- package/dist/mcp/NoopLikeC4MCPServer.js +17 -0
- package/dist/mcp/interfaces.js +5 -0
- package/dist/mcp/server/StdioLikeC4MCPServer.js +47 -0
- package/dist/mcp/server/StreamableLikeC4MCPServer.js +145 -0
- package/dist/mcp/server/WithMCPServer.js +56 -0
- package/dist/mcp/tools/_common.d.ts +8 -7
- package/dist/mcp/tools/_common.js +49 -0
- package/dist/mcp/tools/find-relationships.d.ts +7 -8
- package/dist/mcp/tools/find-relationships.js +150 -0
- package/dist/mcp/tools/list-projects.d.ts +3 -3
- package/dist/mcp/tools/list-projects.js +62 -0
- package/dist/mcp/tools/open-view.d.ts +6 -7
- package/dist/mcp/tools/open-view.js +52 -0
- package/dist/mcp/tools/read-deployment.d.ts +6 -7
- package/dist/mcp/tools/read-deployment.js +132 -0
- package/dist/mcp/tools/read-element.d.ts +6 -7
- package/dist/mcp/tools/read-element.js +194 -0
- package/dist/mcp/tools/read-project-summary.d.ts +5 -6
- package/dist/mcp/tools/read-project-summary.js +176 -0
- package/dist/mcp/tools/read-view.d.ts +6 -7
- package/dist/mcp/tools/read-view.js +203 -0
- package/dist/mcp/tools/search-element.d.ts +3 -3
- package/dist/mcp/tools/search-element.js +177 -0
- package/dist/mcp/utils.d.ts +2 -2
- package/dist/mcp/utils.js +48 -0
- package/dist/model/builder/MergedExtends.js +74 -0
- package/dist/model/builder/MergedSpecification.js +175 -0
- package/dist/model/builder/buildModel.js +176 -0
- package/dist/model/deployments-index.js +102 -0
- package/dist/model/fqn-index.js +250 -0
- package/dist/model/index.js +6 -0
- package/dist/model/model-builder.d.ts +13 -11
- package/dist/model/model-builder.js +234 -0
- package/dist/model/model-locator.d.ts +6 -5
- package/dist/model/model-locator.js +240 -0
- package/dist/model/model-parser-where.js +81 -0
- package/dist/model/model-parser.d.ts +309 -304
- package/dist/model/model-parser.js +119 -0
- package/dist/model/parser/Base.d.ts +2 -2
- package/dist/model/parser/Base.js +367 -0
- package/dist/model/parser/DeploymentModelParser.d.ts +2 -2
- package/dist/model/parser/DeploymentModelParser.js +176 -0
- package/dist/model/parser/DeploymentViewParser.d.ts +3 -3
- package/dist/model/parser/DeploymentViewParser.js +86 -0
- package/dist/model/parser/FqnRefParser.d.ts +2 -2
- package/dist/model/parser/FqnRefParser.js +382 -0
- package/dist/model/parser/GlobalsParser.d.ts +6 -6
- package/dist/model/parser/GlobalsParser.js +84 -0
- package/dist/model/parser/ImportsParser.d.ts +11 -12
- package/dist/model/parser/ImportsParser.js +24 -0
- package/dist/model/parser/ModelParser.d.ts +2 -2
- package/dist/model/parser/ModelParser.js +165 -0
- package/dist/model/parser/PredicatesParser.d.ts +2 -2
- package/dist/model/parser/PredicatesParser.js +45 -0
- package/dist/model/parser/SpecificationParser.d.ts +2 -2
- package/dist/model/parser/SpecificationParser.js +109 -0
- package/dist/model/parser/ValueConverter.js +12 -0
- package/dist/model/parser/ViewsParser.d.ts +3 -3
- package/dist/model/parser/ViewsParser.js +477 -0
- package/dist/model-change/ModelChanges.d.ts +6 -3
- package/dist/model-change/ModelChanges.js +102 -0
- package/dist/model-change/changeElementStyle.js +134 -0
- package/dist/model-change/changeViewLayout.d.ts +2 -2
- package/dist/model-change/changeViewLayout.js +28 -0
- package/dist/model-change/removeManualLayoutV1.d.ts +7 -0
- package/dist/model-change/removeManualLayoutV1.js +27 -0
- package/dist/module.d.ts +10 -5
- package/dist/module.js +143 -0
- package/dist/protocol.d.ts +1 -17
- package/dist/protocol.js +114 -0
- package/dist/references/index.js +3 -0
- package/dist/references/name-provider.js +37 -0
- package/dist/references/scope-computation.js +288 -0
- package/dist/references/scope-provider.d.ts +3 -3
- package/dist/references/scope-provider.js +242 -0
- package/dist/shared/NodeKindProvider.js +57 -0
- package/dist/shared/{WorkspaceSymbolProvider.mjs → WorkspaceSymbolProvider.js} +1 -1
- package/dist/shared/index.js +2 -0
- package/dist/test/index.js +1 -0
- package/dist/test/testServices.d.ts +16 -16
- package/dist/test/testServices.js +210 -0
- package/dist/utils/disposable.js +26 -0
- package/dist/utils/elementRef.d.ts +1 -1
- package/dist/utils/elementRef.js +27 -0
- package/dist/utils/fqnRef.js +63 -0
- package/dist/utils/index.js +35 -0
- package/dist/utils/printDocs.js +1 -0
- package/dist/utils/projectId.js +16 -0
- package/dist/utils/stringHash.js +5 -0
- package/dist/validation/DocumentValidator.js +17 -0
- package/dist/validation/_shared.js +26 -0
- package/dist/validation/deployment-checks.js +140 -0
- package/dist/validation/dynamic-view.js +67 -0
- package/dist/validation/element-ref.js +12 -0
- package/dist/validation/element.js +49 -0
- package/dist/validation/imports.js +46 -0
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +157 -0
- package/dist/validation/property-checks.js +108 -0
- package/dist/validation/relation.js +55 -0
- package/dist/validation/specification.js +190 -0
- package/dist/validation/view-predicates/fqn-expr-with.js +43 -0
- package/dist/validation/view-predicates/fqn-ref-expr.js +51 -0
- package/dist/validation/view-predicates/incoming.js +16 -0
- package/dist/validation/view-predicates/index.js +6 -0
- package/dist/validation/view-predicates/outgoing.js +20 -0
- package/dist/validation/view-predicates/relation-expr.js +46 -0
- package/dist/validation/view-predicates/relation-with.js +16 -0
- package/dist/validation/view.d.ts +1 -1
- package/dist/validation/view.js +42 -0
- package/dist/view-utils/assignNavigateTo.js +27 -0
- package/dist/view-utils/index.d.ts +1 -0
- package/dist/view-utils/index.js +2 -0
- package/dist/view-utils/manual-layout.d.ts +6 -0
- package/dist/view-utils/manual-layout.js +151 -0
- package/dist/views/ConfigurableLayouter.js +51 -0
- package/dist/views/LikeC4ManualLayouts.d.ts +28 -0
- package/dist/views/LikeC4ManualLayouts.js +132 -0
- package/dist/views/{likec4-views.d.ts → LikeC4Views.d.ts} +9 -8
- package/dist/views/LikeC4Views.js +200 -0
- package/dist/views/index.d.ts +4 -1
- package/dist/views/index.js +11 -0
- package/dist/workspace/AstNodeDescriptionProvider.js +15 -0
- package/dist/workspace/IndexManager.js +21 -0
- package/dist/workspace/LangiumDocuments.d.ts +1 -1
- package/dist/workspace/LangiumDocuments.js +58 -0
- package/dist/workspace/ProjectsManager.d.ts +8 -3
- package/dist/workspace/ProjectsManager.js +373 -0
- package/dist/workspace/WorkspaceManager.d.ts +3 -2
- package/dist/workspace/WorkspaceManager.js +93 -0
- package/dist/workspace/index.js +5 -0
- package/likec4lib/package.json +1 -1
- package/package.json +25 -24
- package/protocol/package.json +1 -1
- package/dist/LikeC4LanguageServices.mjs +0 -197
- package/dist/Rpc.mjs +0 -296
- package/dist/ast.mjs +0 -221
- package/dist/browser-worker.mjs +0 -2
- package/dist/browser.mjs +0 -32
- package/dist/documentation/documentation-provider.mjs +0 -48
- package/dist/documentation/index.mjs +0 -1
- package/dist/empty.mjs +0 -1
- package/dist/filesystem/ChokidarWatcher.mjs +0 -68
- package/dist/filesystem/FileSystemWatcher.mjs +0 -11
- package/dist/filesystem/LikeC4FileSystem.mjs +0 -64
- package/dist/filesystem/index.mjs +0 -19
- package/dist/formatting/LikeC4Formatter.mjs +0 -511
- package/dist/formatting/utils.mjs +0 -15
- package/dist/generated/ast.mjs +0 -2150
- package/dist/generated/module.mjs +0 -23
- package/dist/index.mjs +0 -50
- package/dist/logger.mjs +0 -82
- package/dist/lsp/CodeLensProvider.mjs +0 -42
- package/dist/lsp/CompletionProvider.mjs +0 -208
- package/dist/lsp/DocumentHighlightProvider.mjs +0 -10
- package/dist/lsp/DocumentLinkProvider.mjs +0 -53
- package/dist/lsp/DocumentSymbolProvider.mjs +0 -287
- package/dist/lsp/HoverProvider.mjs +0 -104
- package/dist/lsp/RenameProvider.mjs +0 -6
- package/dist/lsp/SemanticTokenProvider.mjs +0 -276
- package/dist/lsp/index.mjs +0 -7
- package/dist/mcp/MCPServerFactory.mjs +0 -70
- package/dist/mcp/NoopLikeC4MCPServer.mjs +0 -17
- package/dist/mcp/interfaces.mjs +0 -4
- package/dist/mcp/server/StdioLikeC4MCPServer.mjs +0 -46
- package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +0 -153
- package/dist/mcp/server/WithMCPServer.mjs +0 -58
- package/dist/mcp/tools/_common.mjs +0 -42
- package/dist/mcp/tools/find-relationships.mjs +0 -151
- package/dist/mcp/tools/list-projects.mjs +0 -62
- package/dist/mcp/tools/open-view.mjs +0 -52
- package/dist/mcp/tools/read-deployment.mjs +0 -130
- package/dist/mcp/tools/read-element.mjs +0 -198
- package/dist/mcp/tools/read-project-summary.mjs +0 -178
- package/dist/mcp/tools/read-view.mjs +0 -205
- package/dist/mcp/tools/search-element.mjs +0 -171
- package/dist/mcp/utils.mjs +0 -47
- package/dist/model/builder/MergedExtends.mjs +0 -76
- package/dist/model/builder/MergedSpecification.mjs +0 -205
- package/dist/model/builder/assignTagColors.d.ts +0 -7
- package/dist/model/builder/assignTagColors.mjs +0 -51
- package/dist/model/builder/buildModel.mjs +0 -226
- package/dist/model/deployments-index.mjs +0 -100
- package/dist/model/fqn-index.mjs +0 -243
- package/dist/model/index.mjs +0 -6
- package/dist/model/model-builder.mjs +0 -285
- package/dist/model/model-locator.mjs +0 -239
- package/dist/model/model-parser-where.mjs +0 -81
- package/dist/model/model-parser.mjs +0 -127
- package/dist/model/parser/Base.mjs +0 -376
- package/dist/model/parser/DeploymentModelParser.mjs +0 -212
- package/dist/model/parser/DeploymentViewParser.mjs +0 -95
- package/dist/model/parser/FqnRefParser.mjs +0 -398
- package/dist/model/parser/GlobalsParser.mjs +0 -82
- package/dist/model/parser/ImportsParser.mjs +0 -28
- package/dist/model/parser/ModelParser.mjs +0 -190
- package/dist/model/parser/PredicatesParser.mjs +0 -45
- package/dist/model/parser/SpecificationParser.mjs +0 -120
- package/dist/model/parser/ValueConverter.mjs +0 -12
- package/dist/model/parser/ViewsParser.mjs +0 -490
- package/dist/model-change/ModelChanges.mjs +0 -89
- package/dist/model-change/changeElementStyle.mjs +0 -143
- package/dist/model-change/changeViewLayout.mjs +0 -32
- package/dist/model-change/saveManualLayout.d.ts +0 -11
- package/dist/model-change/saveManualLayout.mjs +0 -27
- package/dist/module.mjs +0 -180
- package/dist/protocol.mjs +0 -65
- package/dist/references/index.mjs +0 -3
- package/dist/references/name-provider.mjs +0 -39
- package/dist/references/scope-computation.mjs +0 -312
- package/dist/references/scope-provider.mjs +0 -239
- package/dist/shared/NodeKindProvider.mjs +0 -110
- package/dist/shared/index.mjs +0 -2
- package/dist/test/index.mjs +0 -1
- package/dist/test/testServices.mjs +0 -200
- package/dist/utils/disposable.mjs +0 -25
- package/dist/utils/elementRef.mjs +0 -20
- package/dist/utils/fqnRef.mjs +0 -57
- package/dist/utils/index.mjs +0 -33
- package/dist/utils/printDocs.mjs +0 -1
- package/dist/utils/projectId.mjs +0 -16
- package/dist/utils/stringHash.mjs +0 -5
- package/dist/validation/DocumentValidator.mjs +0 -16
- package/dist/validation/_shared.mjs +0 -25
- package/dist/validation/deployment-checks.mjs +0 -146
- package/dist/validation/dynamic-view.mjs +0 -67
- package/dist/validation/element-ref.mjs +0 -12
- package/dist/validation/element.mjs +0 -50
- package/dist/validation/imports.mjs +0 -25
- package/dist/validation/index.mjs +0 -180
- package/dist/validation/property-checks.mjs +0 -107
- package/dist/validation/relation.mjs +0 -53
- package/dist/validation/specification.mjs +0 -173
- package/dist/validation/view-predicates/fqn-expr-with.mjs +0 -43
- package/dist/validation/view-predicates/fqn-ref-expr.mjs +0 -53
- package/dist/validation/view-predicates/incoming.mjs +0 -16
- package/dist/validation/view-predicates/index.mjs +0 -6
- package/dist/validation/view-predicates/outgoing.mjs +0 -20
- package/dist/validation/view-predicates/relation-expr.mjs +0 -39
- package/dist/validation/view-predicates/relation-with.mjs +0 -16
- package/dist/validation/view.mjs +0 -25
- package/dist/view-utils/assignNavigateTo.mjs +0 -25
- package/dist/view-utils/index.mjs +0 -1
- package/dist/view-utils/manual-layout.mjs +0 -99
- package/dist/views/configurable-layouter.mjs +0 -51
- package/dist/views/index.mjs +0 -1
- package/dist/views/likec4-views.mjs +0 -166
- package/dist/workspace/AstNodeDescriptionProvider.mjs +0 -17
- package/dist/workspace/IndexManager.mjs +0 -17
- package/dist/workspace/LangiumDocuments.mjs +0 -53
- package/dist/workspace/ProjectsManager.mjs +0 -360
- package/dist/workspace/WorkspaceManager.mjs +0 -83
- package/dist/workspace/index.mjs +0 -5
- /package/dist/views/{configurable-layouter.d.ts → ConfigurableLayouter.d.ts} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { GraphvizWasmAdapter, QueueGraphvizLayoter } from '@likec4/layouts';
|
|
2
|
+
import { GraphvizBinaryAdapter } from '@likec4/layouts/graphviz/binary';
|
|
3
|
+
import { isEmpty } from 'remeda';
|
|
4
|
+
import which from 'which';
|
|
5
|
+
import { logger } from '../logger';
|
|
6
|
+
function graphvizBinPath() {
|
|
7
|
+
try {
|
|
8
|
+
return which.sync('dot');
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
logger.error('Error checking for native Graphviz:', { error });
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export const ConfigurableLayouter = {
|
|
16
|
+
likec4: {
|
|
17
|
+
Layouter(services) {
|
|
18
|
+
logger.debug('Creating ConfigurableLayouter');
|
|
19
|
+
const layouter = new QueueGraphvizLayoter();
|
|
20
|
+
services.shared.workspace.ConfigurationProvider.onConfigurationSectionUpdate((update) => {
|
|
21
|
+
logger.debug('Configuration update: {update}', { update });
|
|
22
|
+
if (update.section !== services.LanguageMetaData.languageId) {
|
|
23
|
+
logger.debug(`Ignoring configuration update as it is not for ${services.LanguageMetaData.languageId}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const { mode, path } = update.configuration.graphviz ?? {
|
|
28
|
+
mode: 'wasm',
|
|
29
|
+
path: '',
|
|
30
|
+
};
|
|
31
|
+
if (mode !== 'wasm') {
|
|
32
|
+
let binaryPath = isEmpty(path) ? graphvizBinPath() : path;
|
|
33
|
+
if (!isEmpty(binaryPath)) {
|
|
34
|
+
layouter.changePort(new GraphvizBinaryAdapter(binaryPath));
|
|
35
|
+
logger.info `use graphviz binary: ${binaryPath}`;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
logger.warn(`No Graphviz binaries found on PATH, use graphviz wasm`);
|
|
39
|
+
services.shared.lsp.Connection?.window.showWarningMessage('No Graphviz binaries found on PATH, set path to binaries in settings.');
|
|
40
|
+
}
|
|
41
|
+
layouter.changePort(new GraphvizWasmAdapter());
|
|
42
|
+
logger.info('use graphviz wasm');
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
logger.error('Failed to update configuration', { error });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return layouter;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { LayoutedView, ViewId } from '@likec4/core';
|
|
2
|
+
import { type Location } from 'vscode-languageserver-types';
|
|
3
|
+
import type { LikeC4Services } from '../module';
|
|
4
|
+
import type { Project } from '../workspace/ProjectsManager';
|
|
5
|
+
/**
|
|
6
|
+
* @todo sync with vscode extension watchers
|
|
7
|
+
* (search for ".likec4.snap" references)
|
|
8
|
+
*/
|
|
9
|
+
export declare const isManualLayoutFile: (path: string) => boolean;
|
|
10
|
+
export interface LikeC4ManualLayouts {
|
|
11
|
+
read(project: Project): Promise<Record<ViewId, LayoutedView> | null>;
|
|
12
|
+
write(project: Project, layouted: LayoutedView): Promise<Location>;
|
|
13
|
+
remove(project: Project, view: ViewId): Promise<Location | null>;
|
|
14
|
+
clearCaches(): void;
|
|
15
|
+
}
|
|
16
|
+
export interface LikeC4ManualLayoutsModuleContext {
|
|
17
|
+
manualLayouts: (services: LikeC4Services) => LikeC4ManualLayouts;
|
|
18
|
+
}
|
|
19
|
+
export declare const WithLikeC4ManualLayouts: LikeC4ManualLayoutsModuleContext;
|
|
20
|
+
export declare class DefaultLikeC4ManualLayouts implements LikeC4ManualLayouts {
|
|
21
|
+
private services;
|
|
22
|
+
private manualLayouts;
|
|
23
|
+
constructor(services: LikeC4Services);
|
|
24
|
+
read(project: Project): Promise<Record<ViewId, LayoutedView> | null>;
|
|
25
|
+
write(project: Project, layouted: LayoutedView): Promise<Location>;
|
|
26
|
+
remove(project: Project, view: ViewId): Promise<Location | null>;
|
|
27
|
+
clearCaches(): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { getOrCreate } from '@likec4/core/utils';
|
|
2
|
+
import JSON5 from 'json5';
|
|
3
|
+
import { UriUtils } from 'langium';
|
|
4
|
+
import { indexBy, prop } from 'remeda';
|
|
5
|
+
import { Position, Range, } from 'vscode-languageserver-types';
|
|
6
|
+
import { logger as rootLogger } from '../logger';
|
|
7
|
+
const logger = rootLogger.getChild('manual-layouts');
|
|
8
|
+
/**
|
|
9
|
+
* @todo sync with vscode extension watchers
|
|
10
|
+
* (search for ".likec4.snap" references)
|
|
11
|
+
*/
|
|
12
|
+
export const isManualLayoutFile = (path) => path.endsWith('.likec4.snap');
|
|
13
|
+
function fileName(view) {
|
|
14
|
+
return `${view}.likec4.snap`;
|
|
15
|
+
}
|
|
16
|
+
function getManualLayoutsOutDir(project) {
|
|
17
|
+
return UriUtils.resolvePath(project.folderUri, project.config.manualLayouts?.outDir ?? '.likec4');
|
|
18
|
+
}
|
|
19
|
+
export const WithLikeC4ManualLayouts = {
|
|
20
|
+
manualLayouts: (services) => new DefaultLikeC4ManualLayouts(services),
|
|
21
|
+
};
|
|
22
|
+
export class DefaultLikeC4ManualLayouts {
|
|
23
|
+
services;
|
|
24
|
+
manualLayouts = new WeakMap();
|
|
25
|
+
constructor(services) {
|
|
26
|
+
this.services = services;
|
|
27
|
+
}
|
|
28
|
+
async read(project) {
|
|
29
|
+
return await getOrCreate(this.manualLayouts, project.folderUri, async (_) => {
|
|
30
|
+
const fs = this.services.shared.workspace.FileSystemProvider;
|
|
31
|
+
const outDir = getManualLayoutsOutDir(project);
|
|
32
|
+
const manualLayouts = [];
|
|
33
|
+
try {
|
|
34
|
+
const files = await fs.scanDirectory(outDir, isManualLayoutFile);
|
|
35
|
+
if (files.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
for (const file of files) {
|
|
39
|
+
if (file.isFile) {
|
|
40
|
+
try {
|
|
41
|
+
const content = await fs.readFile(file.uri);
|
|
42
|
+
manualLayouts.push({
|
|
43
|
+
...JSON5.parse(content),
|
|
44
|
+
_layout: 'manual',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
logger.warn(`Failed to read view snapshot ${file.uri.fsPath}`, { err });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (manualLayouts.length) {
|
|
53
|
+
logger.debug `read manual layouts for ${project.id}, found ${manualLayouts.length}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
logger.warn(`Failed to read manual layouts for ${project.folderUri.fsPath}`, { err });
|
|
58
|
+
}
|
|
59
|
+
if (manualLayouts.length === 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return indexBy(manualLayouts, prop('id'));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async write(project, layouted) {
|
|
66
|
+
const outDir = getManualLayoutsOutDir(project);
|
|
67
|
+
const file = UriUtils.joinPath(outDir, fileName(layouted.id));
|
|
68
|
+
// Ensure the manualLayout field is omitted (may exist in migration)
|
|
69
|
+
if ('manualLayout' in layouted) {
|
|
70
|
+
const { manualLayout: _, ...rest } = layouted;
|
|
71
|
+
layouted = rest;
|
|
72
|
+
}
|
|
73
|
+
const content = JSON5.stringify(layouted, {
|
|
74
|
+
space: 2,
|
|
75
|
+
quote: '\'',
|
|
76
|
+
});
|
|
77
|
+
const location = {
|
|
78
|
+
uri: file.toString(),
|
|
79
|
+
range: Range.create(Position.create(0, 0), Position.create(content.split('\n').length - 1, 1)),
|
|
80
|
+
};
|
|
81
|
+
logger.debug `write snapshot of ${layouted.id} in project ${project.id} to ${file.fsPath}`;
|
|
82
|
+
const fs = this.services.shared.workspace.FileSystemProvider;
|
|
83
|
+
try {
|
|
84
|
+
await fs.writeFile(file, content);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
logger.warn(`Failed to write snapshot ${layouted.id} to ${file.fsPath}`, { err });
|
|
88
|
+
}
|
|
89
|
+
const projectCaches = await this.read(project);
|
|
90
|
+
if (projectCaches) {
|
|
91
|
+
logger.debug `update snapshot cache of ${layouted.id} in project ${project.id}`;
|
|
92
|
+
projectCaches[layouted.id] = layouted;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.manualLayouts.delete(project.folderUri);
|
|
96
|
+
}
|
|
97
|
+
this.services.likec4.ModelBuilder.clearCache();
|
|
98
|
+
return location;
|
|
99
|
+
}
|
|
100
|
+
async remove(project, view) {
|
|
101
|
+
const outDir = getManualLayoutsOutDir(project);
|
|
102
|
+
const file = UriUtils.joinPath(outDir, fileName(view));
|
|
103
|
+
logger.debug `delete snapshot of ${view} in project ${project.id}. File: ${file.fsPath}`;
|
|
104
|
+
const location = {
|
|
105
|
+
uri: file.toString(),
|
|
106
|
+
range: Range.create(0, 0, 0, 0),
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
const fs = this.services.shared.workspace.FileSystemProvider;
|
|
110
|
+
if (!(await fs.deleteFile(file))) {
|
|
111
|
+
logger.warn `Snapshot ${view} did not exist at ${file.fsPath}`;
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
logger.warn(`Failed to delete snapshot ${view} from ${file.fsPath}`, { err });
|
|
117
|
+
}
|
|
118
|
+
const projectCaches = await this.read(project);
|
|
119
|
+
if (projectCaches) {
|
|
120
|
+
logger.debug `clean cache of ${view} in project ${project.id}`;
|
|
121
|
+
delete projectCaches[view];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
this.manualLayouts.delete(project.folderUri);
|
|
125
|
+
}
|
|
126
|
+
this.services.likec4.ModelBuilder.clearCache();
|
|
127
|
+
return location;
|
|
128
|
+
}
|
|
129
|
+
clearCaches() {
|
|
130
|
+
this.manualLayouts = new WeakMap();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { ComputedView, DiagramView, ProjectId, ViewId } from '@likec4/core';
|
|
1
|
+
import type { ComputedView, DiagramView, LayoutedView, ProjectId, ViewId } from '@likec4/core';
|
|
2
2
|
import { type QueueGraphvizLayoter, GraphvizLayouter } from '@likec4/layouts';
|
|
3
3
|
import type { CancellationToken } from 'vscode-languageserver';
|
|
4
4
|
import type { LikeC4Services } from '../module';
|
|
5
5
|
export type GraphvizOut = {
|
|
6
6
|
readonly dot: string;
|
|
7
|
-
readonly diagram:
|
|
7
|
+
readonly diagram: LayoutedView;
|
|
8
8
|
};
|
|
9
9
|
type GraphvizSvgOut = {
|
|
10
10
|
readonly id: ViewId;
|
|
@@ -18,17 +18,17 @@ export interface LikeC4Views {
|
|
|
18
18
|
*/
|
|
19
19
|
computedViews(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<ComputedView[]>;
|
|
20
20
|
/**
|
|
21
|
-
* Returns all layouted views (
|
|
22
|
-
* Result includes dot and diagram
|
|
21
|
+
* Returns all layouted views (without manual layout)
|
|
23
22
|
*/
|
|
24
23
|
layoutAllViews(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut[]>;
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* Layouts a view (from sources, i.e. without manual layout)
|
|
26
|
+
* If view not found in model, but there is a snapshot - it will be returned (with empty DOT)
|
|
28
27
|
*/
|
|
29
28
|
layoutView(viewId: ViewId, projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut | null>;
|
|
30
29
|
/**
|
|
31
|
-
* Returns diagrams
|
|
30
|
+
* Returns diagrams.
|
|
31
|
+
* If diagram has manual layout, it will be used.
|
|
32
32
|
*/
|
|
33
33
|
diagrams(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<DiagramView>>;
|
|
34
34
|
/**
|
|
@@ -53,9 +53,10 @@ export declare class DefaultLikeC4Views implements LikeC4Views {
|
|
|
53
53
|
constructor(services: LikeC4Services);
|
|
54
54
|
get layouter(): QueueGraphvizLayoter;
|
|
55
55
|
computedViews(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<ComputedView[]>;
|
|
56
|
+
private _layoutAllViews;
|
|
56
57
|
layoutAllViews(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut[]>;
|
|
57
58
|
layoutView(viewId: ViewId, projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut | null>;
|
|
58
|
-
diagrams(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<
|
|
59
|
+
diagrams(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<LayoutedView>>;
|
|
59
60
|
viewsAsGraphvizOut(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<GraphvizSvgOut>>;
|
|
60
61
|
/**
|
|
61
62
|
* Open a view in the preview panel.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { applyLayoutDriftReasons, applyManualLayout } from '@likec4/core/model';
|
|
2
|
+
import { GraphvizLayouter } from '@likec4/layouts';
|
|
3
|
+
import { loggable } from '@likec4/log';
|
|
4
|
+
import { interruptAndCheck } from 'langium';
|
|
5
|
+
import { unique, values } from 'remeda';
|
|
6
|
+
import { logger as rootLogger, logWarnError } from '../logger';
|
|
7
|
+
import { performanceMark } from '../utils';
|
|
8
|
+
const viewsLogger = rootLogger.getChild('views');
|
|
9
|
+
export class DefaultLikeC4Views {
|
|
10
|
+
services;
|
|
11
|
+
cache = new WeakMap();
|
|
12
|
+
/**
|
|
13
|
+
* Set of viewIds with reported errors
|
|
14
|
+
* value is `${projectId}-${viewId}`
|
|
15
|
+
*/
|
|
16
|
+
viewsWithReportedErrors = new Set();
|
|
17
|
+
ModelBuilder;
|
|
18
|
+
constructor(services) {
|
|
19
|
+
this.services = services;
|
|
20
|
+
this.ModelBuilder = services.likec4.ModelBuilder;
|
|
21
|
+
}
|
|
22
|
+
get layouter() {
|
|
23
|
+
return this.services.likec4.Layouter;
|
|
24
|
+
}
|
|
25
|
+
async computedViews(projectId, cancelToken) {
|
|
26
|
+
const likeC4Model = await this.ModelBuilder.computeModel(projectId, cancelToken);
|
|
27
|
+
return values(likeC4Model.$data.views);
|
|
28
|
+
}
|
|
29
|
+
async _layoutAllViews(likeC4Model, cancelToken) {
|
|
30
|
+
const views = values(likeC4Model.$data.views);
|
|
31
|
+
if (views.length === 0) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
const m0 = performanceMark();
|
|
35
|
+
const projectId = likeC4Model.project.id;
|
|
36
|
+
const logger = viewsLogger.getChild(projectId);
|
|
37
|
+
logger.debug `layoutAll: ${views.length} views`;
|
|
38
|
+
const tasks = [];
|
|
39
|
+
const styles = likeC4Model.$styles;
|
|
40
|
+
const results = [];
|
|
41
|
+
//
|
|
42
|
+
for (const view of views) {
|
|
43
|
+
let cached = this.cache.get(view);
|
|
44
|
+
if (cached) {
|
|
45
|
+
logger.debug `layout ${view.id} from cache`;
|
|
46
|
+
results.push(cached);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
tasks.push({
|
|
50
|
+
view,
|
|
51
|
+
styles,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (tasks.length > 0) {
|
|
55
|
+
await this.layouter.batchLayout({
|
|
56
|
+
batch: tasks,
|
|
57
|
+
cancelToken,
|
|
58
|
+
onSuccess: (task, result) => {
|
|
59
|
+
results.push(this.viewSucceed(task.view, likeC4Model, result));
|
|
60
|
+
},
|
|
61
|
+
onError: (task, error) => {
|
|
62
|
+
logger.warn(`Fail layout view ${task.view.id}`, { error });
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (cancelToken && cancelToken.isCancellationRequested) {
|
|
67
|
+
await interruptAndCheck(cancelToken);
|
|
68
|
+
}
|
|
69
|
+
if (results.length !== views.length) {
|
|
70
|
+
logger.warn `layouted ${results.length} of ${views.length} views in ${m0.pretty}`;
|
|
71
|
+
}
|
|
72
|
+
else if (results.length > 0) {
|
|
73
|
+
logger.debug `layouted all ${results.length} views in ${m0.pretty}`;
|
|
74
|
+
}
|
|
75
|
+
return results;
|
|
76
|
+
}
|
|
77
|
+
async layoutAllViews(projectId, cancelToken) {
|
|
78
|
+
const likeC4Model = await this.ModelBuilder.computeModel(projectId, cancelToken);
|
|
79
|
+
return await this._layoutAllViews(likeC4Model, cancelToken);
|
|
80
|
+
}
|
|
81
|
+
async layoutView(viewId, projectId, cancelToken) {
|
|
82
|
+
const model = await this.ModelBuilder.computeModel(projectId, cancelToken);
|
|
83
|
+
const view = model.findView(viewId)?.$view;
|
|
84
|
+
projectId = model.project.id;
|
|
85
|
+
const logger = viewsLogger.getChild(projectId);
|
|
86
|
+
if (!view) {
|
|
87
|
+
logger.warn `layoutView ${viewId} not found`;
|
|
88
|
+
const project = this.services.shared.workspace.ProjectsManager.getProject(projectId);
|
|
89
|
+
const manualLayouts = await this.services.likec4.ManualLayouts.read(project);
|
|
90
|
+
const snapshot = manualLayouts?.[viewId];
|
|
91
|
+
if (snapshot) {
|
|
92
|
+
logger.debug `found manual layout for ${viewId}`;
|
|
93
|
+
return {
|
|
94
|
+
diagram: {
|
|
95
|
+
...snapshot,
|
|
96
|
+
_layout: 'manual',
|
|
97
|
+
drifts: snapshot.drifts
|
|
98
|
+
? unique([
|
|
99
|
+
...snapshot.drifts,
|
|
100
|
+
'not-exists',
|
|
101
|
+
])
|
|
102
|
+
: ['not-exists'],
|
|
103
|
+
},
|
|
104
|
+
dot: '# manual layout',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
let cached = this.cache.get(view);
|
|
110
|
+
if (cached) {
|
|
111
|
+
logger.debug `layout ${viewId} from cache`;
|
|
112
|
+
return await Promise.resolve().then(() => cached);
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const m0 = performanceMark();
|
|
116
|
+
const result = await this.layouter.layout({
|
|
117
|
+
view,
|
|
118
|
+
styles: model.$styles,
|
|
119
|
+
});
|
|
120
|
+
logger.debug(`layout {viewId} ready in ${m0.pretty}`, { viewId });
|
|
121
|
+
return this.viewSucceed(view, model, result);
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
const errMessage = loggable(e);
|
|
125
|
+
logger.warn(errMessage);
|
|
126
|
+
this.reportViewError(view, projectId, errMessage);
|
|
127
|
+
return Promise.reject(e);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async diagrams(projectId, cancelToken) {
|
|
131
|
+
const likeC4Model = await this.ModelBuilder.computeModel(projectId, cancelToken);
|
|
132
|
+
const layouted = await this._layoutAllViews(likeC4Model, cancelToken);
|
|
133
|
+
return layouted.map(({ diagram }) => {
|
|
134
|
+
const manualLayout = likeC4Model.$data.manualLayouts?.[diagram.id];
|
|
135
|
+
if (manualLayout) {
|
|
136
|
+
return applyManualLayout(diagram, manualLayout);
|
|
137
|
+
}
|
|
138
|
+
return diagram;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async viewsAsGraphvizOut(projectId, cancelToken) {
|
|
142
|
+
const KEY = 'All-LayoutedViews-DotWithSvg';
|
|
143
|
+
const cache = this.services.shared.workspace.Cache;
|
|
144
|
+
if (cache.has(KEY)) {
|
|
145
|
+
return await Promise.resolve(cache.get(KEY));
|
|
146
|
+
}
|
|
147
|
+
const likeC4Model = await this.ModelBuilder.computeModel(projectId, cancelToken);
|
|
148
|
+
const views = values(likeC4Model.$data.views);
|
|
149
|
+
if (views.length === 0) {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
const tasks = views.map(async (view) => {
|
|
153
|
+
const { dot, svg } = await this.layouter.svg({
|
|
154
|
+
view,
|
|
155
|
+
styles: likeC4Model.$styles,
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
id: view.id,
|
|
159
|
+
dot,
|
|
160
|
+
svg,
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
const succeed = [];
|
|
164
|
+
const settledResult = await Promise.allSettled(tasks);
|
|
165
|
+
for (const result of settledResult) {
|
|
166
|
+
if (result.status === 'fulfilled') {
|
|
167
|
+
succeed.push(result.value);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
logWarnError(result.reason);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
cache.set(KEY, succeed);
|
|
174
|
+
return succeed;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Open a view in the preview panel.
|
|
178
|
+
*/
|
|
179
|
+
async openView(viewId, projectId) {
|
|
180
|
+
await this.services.Rpc.openView({ viewId, projectId });
|
|
181
|
+
}
|
|
182
|
+
reportViewError(view, projectId, error) {
|
|
183
|
+
const key = `${projectId}-${view.id}`;
|
|
184
|
+
if (!this.viewsWithReportedErrors.has(key)) {
|
|
185
|
+
this.services.shared.lsp.Connection?.window.showErrorMessage(`LikeC4: ${error}`);
|
|
186
|
+
this.viewsWithReportedErrors.add(key);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
viewSucceed(view, likec4model, result) {
|
|
190
|
+
const projectId = likec4model.project.id;
|
|
191
|
+
const key = `${projectId}-${view.id}`;
|
|
192
|
+
const snapshot = likec4model.$data.manualLayouts?.[view.id];
|
|
193
|
+
if (snapshot) {
|
|
194
|
+
result.diagram = applyLayoutDriftReasons(result.diagram, snapshot);
|
|
195
|
+
}
|
|
196
|
+
this.viewsWithReportedErrors.delete(key);
|
|
197
|
+
this.cache.set(view, result);
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
}
|
package/dist/views/index.d.ts
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import type { LikeC4ManualLayouts, LikeC4ManualLayoutsModuleContext } from './LikeC4ManualLayouts';
|
|
2
|
+
export { DefaultLikeC4Views, type LikeC4Views } from './LikeC4Views';
|
|
3
|
+
export type { LikeC4ManualLayouts, LikeC4ManualLayoutsModuleContext };
|
|
4
|
+
export declare const NoopLikeC4ManualLayouts: LikeC4ManualLayoutsModuleContext;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { DefaultLikeC4Views } from './LikeC4Views';
|
|
2
|
+
export const NoopLikeC4ManualLayouts = {
|
|
3
|
+
manualLayouts: () => {
|
|
4
|
+
return {
|
|
5
|
+
read: () => Promise.resolve(null),
|
|
6
|
+
write: () => Promise.reject(new Error('NoopLikeC4ManualLayouts: write operation is not supported')),
|
|
7
|
+
remove: () => Promise.resolve(null),
|
|
8
|
+
clearCaches: () => { },
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AstUtils, DefaultAstNodeDescriptionProvider, } from 'langium';
|
|
2
|
+
export class AstNodeDescriptionProvider extends DefaultAstNodeDescriptionProvider {
|
|
3
|
+
services;
|
|
4
|
+
constructor(services) {
|
|
5
|
+
super(services);
|
|
6
|
+
this.services = services;
|
|
7
|
+
}
|
|
8
|
+
createDescription(node, name, document) {
|
|
9
|
+
const doc = document ?? AstUtils.getDocument(node);
|
|
10
|
+
const description = super.createDescription(node, name, document);
|
|
11
|
+
doc.likec4ProjectId ??= this.services.shared.workspace.ProjectsManager.belongsTo(doc.uri);
|
|
12
|
+
description.likec4ProjectId = doc.likec4ProjectId;
|
|
13
|
+
return description;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DefaultIndexManager, stream } from 'langium';
|
|
2
|
+
export class IndexManager extends DefaultIndexManager {
|
|
3
|
+
services;
|
|
4
|
+
constructor(services) {
|
|
5
|
+
super(services);
|
|
6
|
+
this.services = services;
|
|
7
|
+
}
|
|
8
|
+
async updateContent(document, cancelToken) {
|
|
9
|
+
const projects = this.services.workspace.ProjectsManager;
|
|
10
|
+
// Ensure the document is assigned to a project
|
|
11
|
+
document.likec4ProjectId = projects.belongsTo(document.uri);
|
|
12
|
+
await super.updateContent(document, cancelToken);
|
|
13
|
+
}
|
|
14
|
+
projectElements(projectId, nodeType, uris) {
|
|
15
|
+
const projects = this.services.workspace.ProjectsManager;
|
|
16
|
+
let documentUris = stream(this.symbolIndex.keys());
|
|
17
|
+
return documentUris
|
|
18
|
+
.filter(uri => projects.belongsTo(uri) === projectId && (!uris || uris.has(uri)))
|
|
19
|
+
.flatMap(uri => this.getFileDescriptions(uri, nodeType));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -5,7 +5,7 @@ import { type LikeC4LangiumDocument } from '../ast';
|
|
|
5
5
|
import type { LikeC4SharedServices } from '../module';
|
|
6
6
|
export declare class LangiumDocuments extends DefaultLangiumDocuments {
|
|
7
7
|
protected services: LikeC4SharedServices;
|
|
8
|
-
protected compare:
|
|
8
|
+
protected compare: (a: string | undefined, b: string | undefined) => number;
|
|
9
9
|
constructor(services: LikeC4SharedServices);
|
|
10
10
|
addDocument(document: LangiumDocument): void;
|
|
11
11
|
/**
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { compareNaturalHierarchically } from '@likec4/core/utils';
|
|
2
|
+
import { DefaultLangiumDocuments } from 'langium';
|
|
3
|
+
import { groupBy, prop } from 'remeda';
|
|
4
|
+
import { isLikeC4LangiumDocument } from '../ast';
|
|
5
|
+
import { isLikeC4Builtin } from '../likec4lib';
|
|
6
|
+
/**
|
|
7
|
+
* Compare function for document paths to ensure consistent order
|
|
8
|
+
*/
|
|
9
|
+
const compare = compareNaturalHierarchically('/', true);
|
|
10
|
+
const ensureOrder = (a, b) => compare(a.uri.path, b.uri.path);
|
|
11
|
+
export class LangiumDocuments extends DefaultLangiumDocuments {
|
|
12
|
+
services;
|
|
13
|
+
compare = compareNaturalHierarchically('/', true);
|
|
14
|
+
constructor(services) {
|
|
15
|
+
super(services);
|
|
16
|
+
this.services = services;
|
|
17
|
+
}
|
|
18
|
+
addDocument(document) {
|
|
19
|
+
const uriString = document.uri.toString();
|
|
20
|
+
if (this.documentMap.has(uriString)) {
|
|
21
|
+
throw new Error(`A document with the URI '${uriString}' is already present.`);
|
|
22
|
+
}
|
|
23
|
+
const docs = [...this.documentMap.values(), document].sort(ensureOrder);
|
|
24
|
+
// Clear and re-add documents to ensure consistent order
|
|
25
|
+
this.documentMap.clear();
|
|
26
|
+
for (const doc of docs) {
|
|
27
|
+
this.documentMap.set(doc.uri.toString(), doc);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns all user documents, excluding built-in documents.
|
|
32
|
+
*/
|
|
33
|
+
get allExcludingBuiltin() {
|
|
34
|
+
const projects = this.services.workspace.ProjectsManager;
|
|
35
|
+
return super.all.filter((doc) => {
|
|
36
|
+
if (!isLikeC4LangiumDocument(doc) || isLikeC4Builtin(doc.uri)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
doc.likec4ProjectId = projects.belongsTo(doc.uri);
|
|
40
|
+
return !projects.isExcluded(doc);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
projectDocuments(projectId) {
|
|
44
|
+
return this.allExcludingBuiltin.filter(doc => doc.likec4ProjectId === projectId);
|
|
45
|
+
}
|
|
46
|
+
groupedByProject() {
|
|
47
|
+
return groupBy(this.allExcludingBuiltin.toArray(), prop('likec4ProjectId'));
|
|
48
|
+
}
|
|
49
|
+
resetProjectIds() {
|
|
50
|
+
const projects = this.services.workspace.ProjectsManager;
|
|
51
|
+
this.all.forEach(doc => {
|
|
52
|
+
if (!isLikeC4LangiumDocument(doc) || isLikeC4Builtin(doc.uri)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
doc.likec4ProjectId = projects.belongsTo(doc);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -29,7 +29,7 @@ export declare class ProjectsManager {
|
|
|
29
29
|
* The global project ID used for all documents
|
|
30
30
|
* that are not part of a specific project.
|
|
31
31
|
*/
|
|
32
|
-
static readonly DefaultProjectId: scalar.ProjectId
|
|
32
|
+
static readonly DefaultProjectId: scalar.ProjectId<string>;
|
|
33
33
|
constructor(services: LikeC4SharedServices);
|
|
34
34
|
/**
|
|
35
35
|
* Returns:
|
|
@@ -48,11 +48,15 @@ export declare class ProjectsManager {
|
|
|
48
48
|
* If there are multiple projects and default project is not set, throws an error
|
|
49
49
|
*/
|
|
50
50
|
ensureProjectId(projectId?: scalar.ProjectId | undefined): scalar.ProjectId;
|
|
51
|
+
/**
|
|
52
|
+
* Validates and ensures the project.
|
|
53
|
+
*/
|
|
54
|
+
ensureProject(projectId?: scalar.ProjectId | undefined): Project;
|
|
51
55
|
hasMultipleProjects(): boolean;
|
|
52
56
|
/**
|
|
53
57
|
* Checks if the specified document should be excluded from processing.
|
|
54
58
|
*/
|
|
55
|
-
|
|
59
|
+
isExcluded(document: LangiumDocument | URI | string): boolean;
|
|
56
60
|
/**
|
|
57
61
|
* Checks if it is a config file and it is not excluded by default exclude pattern
|
|
58
62
|
*
|
|
@@ -80,10 +84,11 @@ export declare class ProjectsManager {
|
|
|
80
84
|
private _registerProject;
|
|
81
85
|
belongsTo(document: LangiumDocument | URI | string): scalar.ProjectId;
|
|
82
86
|
reloadProjects(): Promise<void>;
|
|
87
|
+
protected _reloadProjects(): Promise<void>;
|
|
83
88
|
protected uniqueProjectId(name: string): scalar.ProjectId;
|
|
84
89
|
protected resetProjectIds(): void;
|
|
85
90
|
protected rebuidDocuments(cancelToken?: Cancellation.CancellationToken): Promise<void>;
|
|
86
|
-
protected findProjectForDocument(documentUri: string):
|
|
91
|
+
protected findProjectForDocument(documentUri: string): Pick<ProjectData, "id" | "exclude" | "config">;
|
|
87
92
|
protected get mappingsToProject(): WorkspaceCache<string, Pick<ProjectData, 'id' | 'config' | 'exclude'>>;
|
|
88
93
|
}
|
|
89
94
|
export {};
|