Files
infocom-systems-design/node_modules/langium/lib/references/scope-computation.js
2025-10-03 22:27:28 +03:00

85 lines
4.6 KiB
JavaScript

/******************************************************************************
* Copyright 2021-2022 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { CancellationToken } from '../utils/cancellation.js';
import { streamAllContents, streamContents } from '../utils/ast-utils.js';
import { MultiMap } from '../utils/collections.js';
import { interruptAndCheck } from '../utils/promise-utils.js';
/**
* The default scope computation creates and collectes descriptions of the AST nodes to be exported into the
* _global_ scope from the given document. By default those are the document's root AST node and its directly
* contained child nodes.
*
* Besides, it gathers all AST nodes that have a name (according to the `NameProvider` service) and includes them
* in the local scope of their particular container nodes. As a result, for every cross-reference in the AST,
* target elements from the same level (siblings) and further up towards the root (parents and siblings of parents)
* are visible. Elements being nested inside lower levels (children, children of siblings and parents' siblings)
* are _invisible_ by default, but that can be changed by customizing this service.
*/
export class DefaultScopeComputation {
constructor(services) {
this.nameProvider = services.references.NameProvider;
this.descriptions = services.workspace.AstNodeDescriptionProvider;
}
async computeExports(document, cancelToken = CancellationToken.None) {
return this.computeExportsForNode(document.parseResult.value, document, undefined, cancelToken);
}
/**
* Creates {@link AstNodeDescription AstNodeDescriptions} for the given {@link AstNode parentNode} and its children.
* The list of children to be considered is determined by the function parameter {@link children}.
* By default only the direct children of {@link parentNode} are visited, nested nodes are not exported.
*
* @param parentNode AST node to be exported, i.e., of which an {@link AstNodeDescription} shall be added to the returned list.
* @param document The document containing the AST node to be exported.
* @param children A function called with {@link parentNode} as single argument and returning an {@link Iterable} supplying the children to be visited, which must be directly or transitively contained in {@link parentNode}.
* @param cancelToken Indicates when to cancel the current operation.
* @throws `OperationCancelled` if a user action occurs during execution.
* @returns A list of {@link AstNodeDescription AstNodeDescriptions} to be published to index.
*/
async computeExportsForNode(parentNode, document, children = streamContents, cancelToken = CancellationToken.None) {
const exports = [];
this.exportNode(parentNode, exports, document);
for (const node of children(parentNode)) {
await interruptAndCheck(cancelToken);
this.exportNode(node, exports, document);
}
return exports;
}
/**
* Add a single node to the list of exports if it has a name. Override this method to change how
* symbols are exported, e.g. by modifying their exported name.
*/
exportNode(node, exports, document) {
const name = this.nameProvider.getName(node);
if (name) {
exports.push(this.descriptions.createDescription(node, name, document));
}
}
async computeLocalScopes(document, cancelToken = CancellationToken.None) {
const rootNode = document.parseResult.value;
const scopes = new MultiMap();
// Here we navigate the full AST - local scopes shall be available in the whole document
for (const node of streamAllContents(rootNode)) {
await interruptAndCheck(cancelToken);
this.processNode(node, document, scopes);
}
return scopes;
}
/**
* Process a single node during scopes computation. The default implementation makes the node visible
* in the subtree of its container (if the node has a name). Override this method to change this,
* e.g. by increasing the visibility to a higher level in the AST.
*/
processNode(node, document, scopes) {
const container = node.$container;
if (container) {
const name = this.nameProvider.getName(node);
if (name) {
scopes.add(container, this.descriptions.createDescription(node, name, document));
}
}
}
}
//# sourceMappingURL=scope-computation.js.map