+12
@@ -0,0 +1,12 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2023 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.
|
||||
******************************************************************************/
|
||||
export * from './linker.js';
|
||||
export * from './name-provider.js';
|
||||
export * from './references.js';
|
||||
export * from './scope.js';
|
||||
export * from './scope-computation.js';
|
||||
export * from './scope-provider.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/references/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC"}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2023 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.
|
||||
******************************************************************************/
|
||||
export * from './linker.js';
|
||||
export * from './name-provider.js';
|
||||
export * from './references.js';
|
||||
export * from './scope.js';
|
||||
export * from './scope-computation.js';
|
||||
export * from './scope-provider.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/references/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC"}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 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 type { LangiumCoreServices } from '../services.js';
|
||||
import type { AstNode, AstNodeDescription, AstReflection, CstNode, LinkingError, MultiReference, MultiReferenceItem, Reference, ReferenceInfo } from '../syntax-tree.js';
|
||||
import type { AstNodeLocator } from '../workspace/ast-node-locator.js';
|
||||
import type { LangiumDocument, LangiumDocuments } from '../workspace/documents.js';
|
||||
import type { ScopeProvider } from './scope-provider.js';
|
||||
import { CancellationToken } from '../utils/cancellation.js';
|
||||
import type { LangiumProfiler } from '../workspace/profiler.js';
|
||||
/**
|
||||
* Language-specific service for resolving cross-references in the AST.
|
||||
*/
|
||||
export interface Linker {
|
||||
/**
|
||||
* Links all cross-references within the specified document. The default implementation loads only target
|
||||
* elements from documents that are present in the `LangiumDocuments` service. The linked references are
|
||||
* stored in the document's `references` property.
|
||||
*
|
||||
* @param document A LangiumDocument that shall be linked.
|
||||
* @param cancelToken A token for cancelling the operation.
|
||||
*
|
||||
* @throws `OperationCancelled` if a cancellation event is detected
|
||||
*/
|
||||
link(document: LangiumDocument, cancelToken?: CancellationToken): Promise<void>;
|
||||
/**
|
||||
* Unlinks all references within the specified document and removes them from the list of `references`.
|
||||
*
|
||||
* @param document A LangiumDocument that shall be unlinked.
|
||||
*/
|
||||
unlink(document: LangiumDocument): void;
|
||||
/**
|
||||
* Determines a candidate AST node description for linking the given reference.
|
||||
*
|
||||
* @param refInfo Information about the reference.
|
||||
*/
|
||||
getCandidate(refInfo: ReferenceInfo): AstNodeDescription | LinkingError;
|
||||
/**
|
||||
* Determines a candidate AST node description for linking the given reference.
|
||||
*
|
||||
* @param node The AST node containing the reference.
|
||||
* @param refId The reference identifier used to build a scope.
|
||||
* @param reference The actual reference to resolve.
|
||||
*/
|
||||
getCandidates(refInfo: ReferenceInfo): AstNodeDescription[] | LinkingError;
|
||||
/**
|
||||
* Creates a cross reference node being aware of its containing AstNode, the corresponding CstNode,
|
||||
* the cross reference text denoting the target AstNode being already extracted of the document text,
|
||||
* as well as the unique cross reference identifier.
|
||||
*
|
||||
* Default behavior:
|
||||
* - The returned Reference's 'ref' property pointing to the target AstNode is populated lazily on its
|
||||
* first visit.
|
||||
* - If the target AstNode cannot be resolved on the first visit, an error indicator will be installed
|
||||
* and further resolution attempts will *not* be performed.
|
||||
*
|
||||
* @param node The containing AST node
|
||||
* @param property The AST node property being referenced
|
||||
* @param refNode The corresponding CST node
|
||||
* @param refText The cross reference text denoting the target AstNode
|
||||
* @returns the desired Reference node, whose behavior wrt. resolving the cross reference is implementation specific.
|
||||
*/
|
||||
buildReference(node: AstNode, property: string, refNode: CstNode | undefined, refText: string): Reference;
|
||||
buildMultiReference(node: AstNode, property: string, refNode: CstNode | undefined, refText: string): MultiReference;
|
||||
}
|
||||
export declare const RefResolving: unique symbol;
|
||||
export interface DefaultReference extends Reference {
|
||||
_ref?: AstNode | LinkingError | typeof RefResolving;
|
||||
_nodeDescription?: AstNodeDescription;
|
||||
}
|
||||
export interface DefaultMultiReference extends MultiReference {
|
||||
_items: MultiReferenceItem[] | typeof RefResolving | undefined;
|
||||
_linkingError?: LinkingError;
|
||||
}
|
||||
export declare class DefaultLinker implements Linker {
|
||||
protected readonly reflection: AstReflection;
|
||||
protected readonly scopeProvider: ScopeProvider;
|
||||
protected readonly astNodeLocator: AstNodeLocator;
|
||||
protected readonly langiumDocuments: () => LangiumDocuments;
|
||||
protected readonly profiler: LangiumProfiler | undefined;
|
||||
protected readonly languageId: string;
|
||||
constructor(services: LangiumCoreServices);
|
||||
link(document: LangiumDocument, cancelToken?: CancellationToken): Promise<void>;
|
||||
protected doLink(refInfo: ReferenceInfo, document: LangiumDocument): void;
|
||||
unlink(document: LangiumDocument): void;
|
||||
getCandidate(refInfo: ReferenceInfo): AstNodeDescription | LinkingError;
|
||||
getCandidates(refInfo: ReferenceInfo): AstNodeDescription[] | LinkingError;
|
||||
buildReference(node: AstNode, property: string, refNode: CstNode | undefined, refText: string): Reference;
|
||||
buildMultiReference(node: AstNode, property: string, refNode: CstNode | undefined, refText: string): MultiReference;
|
||||
protected throwCyclicReferenceError(node: AstNode, property: string, refText: string): never;
|
||||
protected getLinkedNode(refInfo: ReferenceInfo): {
|
||||
node?: AstNode;
|
||||
descr?: AstNodeDescription;
|
||||
error?: LinkingError;
|
||||
};
|
||||
protected loadAstNode(nodeDescription: AstNodeDescription): AstNode | undefined;
|
||||
protected createLinkingError(refInfo: ReferenceInfo, targetDescription?: AstNodeDescription): LinkingError;
|
||||
}
|
||||
//# sourceMappingURL=linker.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../../src/references/linker.ts"],"names":[],"mappings":"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"}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 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 { isAstNode, isAstNodeDescription, isLinkingError } from '../syntax-tree.js';
|
||||
import { findRootNode, streamAst, streamReferences } from '../utils/ast-utils.js';
|
||||
import { interruptAndCheck } from '../utils/promise-utils.js';
|
||||
import { DocumentState } from '../workspace/documents.js';
|
||||
export const RefResolving = Symbol('RefResolving');
|
||||
export class DefaultLinker {
|
||||
constructor(services) {
|
||||
this.reflection = services.shared.AstReflection;
|
||||
this.langiumDocuments = () => services.shared.workspace.LangiumDocuments;
|
||||
this.scopeProvider = services.references.ScopeProvider;
|
||||
this.astNodeLocator = services.workspace.AstNodeLocator;
|
||||
this.profiler = services.shared.profilers.LangiumProfiler;
|
||||
this.languageId = services.LanguageMetaData.languageId;
|
||||
}
|
||||
async link(document, cancelToken = CancellationToken.None) {
|
||||
if (this.profiler?.isActive('linking')) {
|
||||
const task = this.profiler.createTask('linking', this.languageId);
|
||||
task.start();
|
||||
try {
|
||||
for (const node of streamAst(document.parseResult.value)) {
|
||||
await interruptAndCheck(cancelToken);
|
||||
streamReferences(node).forEach(ref => {
|
||||
const name = `${node.$type}:${ref.property}`;
|
||||
task.startSubTask(name);
|
||||
try {
|
||||
this.doLink(ref, document);
|
||||
}
|
||||
finally {
|
||||
task.stopSubTask(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
finally {
|
||||
task.stop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const node of streamAst(document.parseResult.value)) {
|
||||
await interruptAndCheck(cancelToken);
|
||||
streamReferences(node).forEach(ref => this.doLink(ref, document));
|
||||
}
|
||||
}
|
||||
}
|
||||
doLink(refInfo, document) {
|
||||
const ref = refInfo.reference;
|
||||
// The reference may already have been resolved lazily by accessing its `ref` property.
|
||||
if ('_ref' in ref && ref._ref === undefined) {
|
||||
ref._ref = RefResolving;
|
||||
try {
|
||||
const description = this.getCandidate(refInfo);
|
||||
if (isLinkingError(description)) {
|
||||
ref._ref = description;
|
||||
}
|
||||
else {
|
||||
ref._nodeDescription = description;
|
||||
const linkedNode = this.loadAstNode(description);
|
||||
ref._ref = linkedNode ?? this.createLinkingError(refInfo, description);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`An error occurred while resolving reference to '${ref.$refText}':`, err);
|
||||
const errorMessage = err.message ?? String(err);
|
||||
ref._ref = {
|
||||
info: refInfo,
|
||||
message: `An error occurred while resolving reference to '${ref.$refText}': ${errorMessage}`
|
||||
};
|
||||
}
|
||||
document.references.push(ref);
|
||||
}
|
||||
else if ('_items' in ref && ref._items === undefined) {
|
||||
ref._items = RefResolving;
|
||||
try {
|
||||
const descriptions = this.getCandidates(refInfo);
|
||||
const items = [];
|
||||
if (isLinkingError(descriptions)) {
|
||||
ref._linkingError = descriptions;
|
||||
}
|
||||
else {
|
||||
for (const description of descriptions) {
|
||||
const linkedNode = this.loadAstNode(description);
|
||||
if (linkedNode) {
|
||||
items.push({ ref: linkedNode, $nodeDescription: description });
|
||||
}
|
||||
}
|
||||
}
|
||||
ref._items = items;
|
||||
}
|
||||
catch (err) {
|
||||
ref._linkingError = {
|
||||
info: refInfo,
|
||||
message: `An error occurred while resolving reference to '${ref.$refText}': ${err}`
|
||||
};
|
||||
ref._items = [];
|
||||
}
|
||||
document.references.push(ref);
|
||||
}
|
||||
}
|
||||
unlink(document) {
|
||||
for (const ref of document.references) {
|
||||
if ('_ref' in ref) {
|
||||
ref._ref = undefined;
|
||||
delete ref._nodeDescription;
|
||||
}
|
||||
else if ('_items' in ref) {
|
||||
ref._items = undefined;
|
||||
delete ref._linkingError;
|
||||
}
|
||||
}
|
||||
document.references = [];
|
||||
}
|
||||
getCandidate(refInfo) {
|
||||
const scope = this.scopeProvider.getScope(refInfo);
|
||||
const description = scope.getElement(refInfo.reference.$refText);
|
||||
return description ?? this.createLinkingError(refInfo);
|
||||
}
|
||||
getCandidates(refInfo) {
|
||||
const scope = this.scopeProvider.getScope(refInfo);
|
||||
const descriptions = scope.getElements(refInfo.reference.$refText).distinct(desc => `${desc.documentUri}#${desc.path}`).toArray();
|
||||
return descriptions.length > 0 ? descriptions : this.createLinkingError(refInfo);
|
||||
}
|
||||
buildReference(node, property, refNode, refText) {
|
||||
// See behavior description in doc of Linker, update that on changes in here.
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const linker = this;
|
||||
const reference = {
|
||||
$refNode: refNode,
|
||||
$refText: refText,
|
||||
_ref: undefined,
|
||||
get ref() {
|
||||
if (isAstNode(this._ref)) {
|
||||
// Most frequent case: the target is already resolved.
|
||||
return this._ref;
|
||||
}
|
||||
else if (isAstNodeDescription(this._nodeDescription)) {
|
||||
// A candidate has been found before, but it is not loaded yet.
|
||||
const linkedNode = linker.loadAstNode(this._nodeDescription);
|
||||
this._ref = linkedNode ??
|
||||
linker.createLinkingError({ reference, container: node, property }, this._nodeDescription);
|
||||
}
|
||||
else if (this._ref === undefined) {
|
||||
// The reference has not been linked yet, so do that now.
|
||||
this._ref = RefResolving;
|
||||
const document = findRootNode(node).$document;
|
||||
const refData = linker.getLinkedNode({ reference, container: node, property });
|
||||
if (refData.error && document && document.state < DocumentState.ComputedScopes) {
|
||||
// Document scope is not ready, don't set `this._ref` so linker can retry later.
|
||||
return this._ref = undefined;
|
||||
}
|
||||
this._ref = refData.node ?? refData.error;
|
||||
this._nodeDescription = refData.descr;
|
||||
document?.references.push(this);
|
||||
}
|
||||
else if (this._ref === RefResolving) {
|
||||
linker.throwCyclicReferenceError(node, property, refText);
|
||||
}
|
||||
return isAstNode(this._ref) ? this._ref : undefined;
|
||||
},
|
||||
get $nodeDescription() {
|
||||
return this._nodeDescription;
|
||||
},
|
||||
get error() {
|
||||
return isLinkingError(this._ref) ? this._ref : undefined;
|
||||
}
|
||||
};
|
||||
return reference;
|
||||
}
|
||||
buildMultiReference(node, property, refNode, refText) {
|
||||
// See behavior description in doc of Linker, update that on changes in here.
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const linker = this;
|
||||
const reference = {
|
||||
$refNode: refNode,
|
||||
$refText: refText,
|
||||
_items: undefined,
|
||||
get items() {
|
||||
if (Array.isArray(this._items)) {
|
||||
return this._items;
|
||||
}
|
||||
else if (this._items === undefined) {
|
||||
this._items = RefResolving;
|
||||
const document = findRootNode(node).$document;
|
||||
const descriptions = linker.getCandidates({
|
||||
reference,
|
||||
container: node,
|
||||
property
|
||||
});
|
||||
const items = [];
|
||||
if (isLinkingError(descriptions)) {
|
||||
this._linkingError = descriptions;
|
||||
}
|
||||
else {
|
||||
for (const description of descriptions) {
|
||||
const linkedNode = linker.loadAstNode(description);
|
||||
if (linkedNode) {
|
||||
items.push({ ref: linkedNode, $nodeDescription: description });
|
||||
}
|
||||
}
|
||||
}
|
||||
this._items = items;
|
||||
document?.references.push(this);
|
||||
}
|
||||
else if (this._items === RefResolving) {
|
||||
linker.throwCyclicReferenceError(node, property, refText);
|
||||
}
|
||||
return Array.isArray(this._items) ? this._items : [];
|
||||
},
|
||||
get error() {
|
||||
if (this._linkingError) {
|
||||
return this._linkingError;
|
||||
}
|
||||
const refs = this.items;
|
||||
if (refs.length > 0) {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
return (this._linkingError = linker.createLinkingError({ reference, container: node, property }));
|
||||
}
|
||||
}
|
||||
};
|
||||
return reference;
|
||||
}
|
||||
throwCyclicReferenceError(node, property, refText) {
|
||||
throw new Error(`Cyclic reference resolution detected: ${this.astNodeLocator.getAstNodePath(node)}/${property} (symbol '${refText}')`);
|
||||
}
|
||||
getLinkedNode(refInfo) {
|
||||
try {
|
||||
const description = this.getCandidate(refInfo);
|
||||
if (isLinkingError(description)) {
|
||||
return { error: description };
|
||||
}
|
||||
const linkedNode = this.loadAstNode(description);
|
||||
if (linkedNode) {
|
||||
return { node: linkedNode, descr: description };
|
||||
}
|
||||
else {
|
||||
return {
|
||||
descr: description,
|
||||
error: this.createLinkingError(refInfo, description)
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`An error occurred while resolving reference to '${refInfo.reference.$refText}':`, err);
|
||||
const errorMessage = err.message ?? String(err);
|
||||
return {
|
||||
error: {
|
||||
info: refInfo,
|
||||
message: `An error occurred while resolving reference to '${refInfo.reference.$refText}': ${errorMessage}`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
loadAstNode(nodeDescription) {
|
||||
if (nodeDescription.node) {
|
||||
return nodeDescription.node;
|
||||
}
|
||||
const doc = this.langiumDocuments().getDocument(nodeDescription.documentUri);
|
||||
if (!doc) {
|
||||
return undefined;
|
||||
}
|
||||
return this.astNodeLocator.getAstNode(doc.parseResult.value, nodeDescription.path);
|
||||
}
|
||||
createLinkingError(refInfo, targetDescription) {
|
||||
// Check whether the document is sufficiently processed by the DocumentBuilder. If not, this is a hint for a bug
|
||||
// in the language implementation.
|
||||
const document = findRootNode(refInfo.container).$document;
|
||||
if (document && document.state < DocumentState.ComputedScopes) {
|
||||
console.warn(`Attempted reference resolution before document reached ComputedScopes state (${document.uri}).`);
|
||||
}
|
||||
const referenceType = this.reflection.getReferenceType(refInfo);
|
||||
return {
|
||||
info: refInfo,
|
||||
message: `Could not resolve reference to ${referenceType} named '${refInfo.reference.$refText}'.`,
|
||||
targetDescription
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=linker.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+30
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 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 type { AstNode, CstNode } from '../syntax-tree.js';
|
||||
export interface NamedAstNode extends AstNode {
|
||||
name: string;
|
||||
}
|
||||
export declare function isNamed(node: AstNode): node is NamedAstNode;
|
||||
/**
|
||||
* Utility service for retrieving the `name` of an `AstNode` or the `CstNode` containing a `name`.
|
||||
*/
|
||||
export interface NameProvider {
|
||||
/**
|
||||
* Returns the `name` of a given AstNode.
|
||||
* @param node Specified `AstNode` whose name node shall be retrieved.
|
||||
*/
|
||||
getName(node: AstNode): string | undefined;
|
||||
/**
|
||||
* Returns the `CstNode` which contains the parsed value of the `name` assignment.
|
||||
* @param node Specified `AstNode` whose name node shall be retrieved.
|
||||
*/
|
||||
getNameNode(node: AstNode): CstNode | undefined;
|
||||
}
|
||||
export declare class DefaultNameProvider implements NameProvider {
|
||||
getName(node: AstNode): string | undefined;
|
||||
getNameNode(node: AstNode): CstNode | undefined;
|
||||
}
|
||||
//# sourceMappingURL=name-provider.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"name-provider.d.ts","sourceRoot":"","sources":["../../src/references/name-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAG1D,MAAM,WAAW,YAAa,SAAQ,OAAO;IACzC,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE3D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAC3C;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;CACnD;AAED,qBAAa,mBAAoB,YAAW,YAAY;IACpD,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IAO1C,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS;CAGlD"}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 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 { findNodeForProperty } from '../utils/grammar-utils.js';
|
||||
export function isNamed(node) {
|
||||
return typeof node.name === 'string';
|
||||
}
|
||||
export class DefaultNameProvider {
|
||||
getName(node) {
|
||||
if (isNamed(node)) {
|
||||
return node.name;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
getNameNode(node) {
|
||||
return findNodeForProperty(node.$cstNode, 'name');
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=name-provider.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"name-provider.js","sourceRoot":"","sources":["../../src/references/name-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAGhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAMhE,MAAM,UAAU,OAAO,CAAC,IAAa;IACjC,OAAO,OAAQ,IAAqB,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC3D,CAAC;AAkBD,MAAM,OAAO,mBAAmB;IAC5B,OAAO,CAAC,IAAa;QACjB,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,IAAI,CAAC;QACrB,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,WAAW,CAAC,IAAa;QACrB,OAAO,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;CACJ"}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 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 type { LangiumCoreServices } from '../services.js';
|
||||
import type { AstNode, CstNode } from '../syntax-tree.js';
|
||||
import type { Stream } from '../utils/stream.js';
|
||||
import type { ReferenceDescription } from '../workspace/ast-descriptions.js';
|
||||
import type { AstNodeLocator } from '../workspace/ast-node-locator.js';
|
||||
import type { IndexManager } from '../workspace/index-manager.js';
|
||||
import type { NameProvider } from './name-provider.js';
|
||||
import type { URI } from '../utils/uri-utils.js';
|
||||
import type { LangiumDocuments } from '../workspace/documents.js';
|
||||
/**
|
||||
* Language-specific service for finding references and declaration of a given `CstNode`.
|
||||
*/
|
||||
export interface References {
|
||||
/**
|
||||
* If the CstNode is a reference node the target AstNodes will be returned.
|
||||
* If the CstNode is a significant node of the CstNode this AstNode will be returned.
|
||||
*
|
||||
* @param sourceCstNode CstNode that points to a AstNode
|
||||
*/
|
||||
findDeclarations(sourceCstNode: CstNode): AstNode[];
|
||||
/**
|
||||
* If the CstNode is a reference node the target CstNodes will be returned.
|
||||
* If the CstNode is a significant node of the CstNode this CstNode will be returned.
|
||||
*
|
||||
* @param sourceCstNode CstNode that points to a AstNode
|
||||
*/
|
||||
findDeclarationNodes(sourceCstNode: CstNode): CstNode[];
|
||||
/**
|
||||
* Finds all references to the target node as references (local references) or reference descriptions.
|
||||
*
|
||||
* @param targetNode Specified target node whose references should be returned
|
||||
*/
|
||||
findReferences(targetNode: AstNode, options: FindReferencesOptions): Stream<ReferenceDescription>;
|
||||
}
|
||||
export interface FindReferencesOptions {
|
||||
/**
|
||||
* When set, the `findReferences` method will only return references/declarations from the specified document.
|
||||
*/
|
||||
documentUri?: URI;
|
||||
/**
|
||||
* Whether the returned list of references should include the declaration.
|
||||
*/
|
||||
includeDeclaration?: boolean;
|
||||
}
|
||||
export declare class DefaultReferences implements References {
|
||||
protected readonly nameProvider: NameProvider;
|
||||
protected readonly index: IndexManager;
|
||||
protected readonly nodeLocator: AstNodeLocator;
|
||||
protected readonly documents: LangiumDocuments;
|
||||
protected hasMultiReference: boolean;
|
||||
constructor(services: LangiumCoreServices);
|
||||
findDeclarations(sourceCstNode: CstNode): AstNode[];
|
||||
/**
|
||||
* Returns all self-references for the specified node.
|
||||
* Since the node can be part of a multi-reference, this method returns all nodes that are part of the same multi-reference.
|
||||
*/
|
||||
protected getSelfNodes(node: AstNode): AstNode[];
|
||||
protected getNodeFromReferenceDescription(ref?: ReferenceDescription): AstNode | undefined;
|
||||
findDeclarationNodes(sourceCstNode: CstNode): CstNode[];
|
||||
findReferences(targetNode: AstNode, options: FindReferencesOptions): Stream<ReferenceDescription>;
|
||||
protected getSelfReferences(targetNode: AstNode): ReferenceDescription[];
|
||||
}
|
||||
//# sourceMappingURL=references.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"references.d.ts","sourceRoot":"","sources":["../../src/references/references.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAkB,MAAM,mBAAmB,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAQjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,UAAU;IAEvB;;;;;OAKG;IACH,gBAAgB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAEpD;;;;;OAKG;IACH,oBAAoB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAExD;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;CACrG;AAED,MAAM,WAAW,qBAAqB;IAClC;;OAEG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,qBAAa,iBAAkB,YAAW,UAAU;IAChD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IACvC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IAC/C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IAC/C,SAAS,CAAC,iBAAiB,EAAE,OAAO,CAAC;gBAEzB,QAAQ,EAAE,mBAAmB;IAQzC,gBAAgB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,EAAE;IA8BnD;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,EAAE;IAwBhD,SAAS,CAAC,+BAA+B,CAAC,GAAG,CAAC,EAAE,oBAAoB,GAAG,OAAO,GAAG,SAAS;IAW1F,oBAAoB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,EAAE;IAYvD,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAajG,SAAS,CAAC,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,oBAAoB,EAAE;CAoB3E"}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 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 { findAssignment } from '../utils/grammar-utils.js';
|
||||
import { isMultiReference, isReference } from '../syntax-tree.js';
|
||||
import { getDocument, getReferenceNodes, streamAst, streamReferences } from '../utils/ast-utils.js';
|
||||
import { isChildNode, toDocumentSegment } from '../utils/cst-utils.js';
|
||||
import { stream } from '../utils/stream.js';
|
||||
import { UriUtils } from '../utils/uri-utils.js';
|
||||
import { isCrossReference } from '../languages/generated/ast.js';
|
||||
export class DefaultReferences {
|
||||
constructor(services) {
|
||||
this.nameProvider = services.references.NameProvider;
|
||||
this.index = services.shared.workspace.IndexManager;
|
||||
this.nodeLocator = services.workspace.AstNodeLocator;
|
||||
this.documents = services.shared.workspace.LangiumDocuments;
|
||||
this.hasMultiReference = streamAst(services.Grammar).some(node => isCrossReference(node) && node.isMulti);
|
||||
}
|
||||
findDeclarations(sourceCstNode) {
|
||||
if (sourceCstNode) {
|
||||
const assignment = findAssignment(sourceCstNode);
|
||||
const nodeElem = sourceCstNode.astNode;
|
||||
if (assignment && nodeElem) {
|
||||
const reference = nodeElem[assignment.feature];
|
||||
if (isReference(reference) || isMultiReference(reference)) {
|
||||
return getReferenceNodes(reference);
|
||||
}
|
||||
else if (Array.isArray(reference)) {
|
||||
for (const ref of reference) {
|
||||
if ((isReference(ref) || isMultiReference(ref)) && ref.$refNode
|
||||
&& ref.$refNode.offset <= sourceCstNode.offset
|
||||
&& ref.$refNode.end >= sourceCstNode.end) {
|
||||
return getReferenceNodes(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodeElem) {
|
||||
const nameNode = this.nameProvider.getNameNode(nodeElem);
|
||||
// Only return the targeted node in case the targeted cst node is the name node or part of it
|
||||
if (nameNode && (nameNode === sourceCstNode || isChildNode(sourceCstNode, nameNode))) {
|
||||
return this.getSelfNodes(nodeElem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* Returns all self-references for the specified node.
|
||||
* Since the node can be part of a multi-reference, this method returns all nodes that are part of the same multi-reference.
|
||||
*/
|
||||
getSelfNodes(node) {
|
||||
if (!this.hasMultiReference) {
|
||||
return [node];
|
||||
}
|
||||
else {
|
||||
// In order to find all nodes that are part of the same multi-reference,
|
||||
// we need to find a reference that points to the node.
|
||||
// It will also point to the logical siblings of the node.
|
||||
const references = this.index.findAllReferences(node, this.nodeLocator.getAstNodePath(node));
|
||||
// We can simply use the first reference to find all logical siblings.
|
||||
// Looking through all references is not necessary and very inefficient.
|
||||
const headNode = this.getNodeFromReferenceDescription(references.head());
|
||||
if (headNode) {
|
||||
// We need to iterate over all references to find the one that points to the node.
|
||||
for (const ref of streamReferences(headNode)) {
|
||||
if (isMultiReference(ref.reference) && ref.reference.items.some(item => item.ref === node)) {
|
||||
// Once we found the reference, simply return all items of the multi-reference.
|
||||
return ref.reference.items.map(item => item.ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [node];
|
||||
}
|
||||
}
|
||||
getNodeFromReferenceDescription(ref) {
|
||||
if (!ref) {
|
||||
return undefined;
|
||||
}
|
||||
const doc = this.documents.getDocument(ref.sourceUri);
|
||||
if (doc) {
|
||||
return this.nodeLocator.getAstNode(doc.parseResult.value, ref.sourcePath);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
findDeclarationNodes(sourceCstNode) {
|
||||
const astNodes = this.findDeclarations(sourceCstNode);
|
||||
const cstNodes = [];
|
||||
for (const astNode of astNodes) {
|
||||
const cstNode = this.nameProvider.getNameNode(astNode) ?? astNode.$cstNode;
|
||||
if (cstNode) {
|
||||
cstNodes.push(cstNode);
|
||||
}
|
||||
}
|
||||
return cstNodes;
|
||||
}
|
||||
findReferences(targetNode, options) {
|
||||
const refs = [];
|
||||
if (options.includeDeclaration) {
|
||||
refs.push(...this.getSelfReferences(targetNode));
|
||||
}
|
||||
let indexReferences = this.index.findAllReferences(targetNode, this.nodeLocator.getAstNodePath(targetNode));
|
||||
if (options.documentUri) {
|
||||
indexReferences = indexReferences.filter(ref => UriUtils.equals(ref.sourceUri, options.documentUri));
|
||||
}
|
||||
refs.push(...indexReferences);
|
||||
return stream(refs);
|
||||
}
|
||||
getSelfReferences(targetNode) {
|
||||
const selfNodes = this.getSelfNodes(targetNode);
|
||||
const references = [];
|
||||
for (const selfNode of selfNodes) {
|
||||
const nameNode = this.nameProvider.getNameNode(selfNode);
|
||||
if (nameNode) {
|
||||
const doc = getDocument(selfNode);
|
||||
const path = this.nodeLocator.getAstNodePath(selfNode);
|
||||
references.push({
|
||||
sourceUri: doc.uri,
|
||||
sourcePath: path,
|
||||
targetUri: doc.uri,
|
||||
targetPath: path,
|
||||
segment: toDocumentSegment(nameNode),
|
||||
local: true
|
||||
});
|
||||
}
|
||||
}
|
||||
return references;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=references.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"references.js","sourceRoot":"","sources":["../../src/references/references.ts"],"names":[],"mappings":"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"}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/******************************************************************************
|
||||
* 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 type { LangiumCoreServices } from '../services.js';
|
||||
import type { AstNode, AstNodeDescription } from '../syntax-tree.js';
|
||||
import { CancellationToken } from '../utils/cancellation.js';
|
||||
import { MultiMap } from '../utils/collections.js';
|
||||
import type { AstNodeDescriptionProvider } from '../workspace/ast-descriptions.js';
|
||||
import type { LangiumDocument, LocalSymbols } from '../workspace/documents.js';
|
||||
import type { NameProvider } from './name-provider.js';
|
||||
/**
|
||||
* Language-specific service for precomputing global and local scopes. The service methods are executed
|
||||
* as the first and second phase in the `DocumentBuilder`.
|
||||
*/
|
||||
export interface ScopeComputation {
|
||||
/**
|
||||
* Creates descriptions of all AST nodes that shall be exported into the _global_ scope from the given
|
||||
* document. These descriptions are gathered by the `IndexManager` and stored in the global index so
|
||||
* they can be referenced from other documents.
|
||||
*
|
||||
* _Note:_ You should not resolve any cross-references in this service method. Cross-reference resolution
|
||||
* depends on the scope computation phase to be completed (`computeScope` method), which runs after the
|
||||
* initial indexing where this method is used.
|
||||
*
|
||||
* @param document The document from which to gather exported AST nodes.
|
||||
* @param cancelToken Indicates when to cancel the current operation.
|
||||
* @throws `OperationCanceled` if a user action occurs during execution
|
||||
*/
|
||||
collectExportedSymbols(document: LangiumDocument, cancelToken?: CancellationToken): Promise<AstNodeDescription[]>;
|
||||
/**
|
||||
* Creates descriptions of the _local_ symbols being accessible within a document.
|
||||
* The result is a `LocalSymbols` table assigning sets of AST node descriptions to the corresponding
|
||||
* nodes/subtrees within the AST. The descriptions are considered in the default reference resolution
|
||||
* implementation, i.e. they are used by the `ScopeProvider` service to determine which symbols
|
||||
* are visible in the context of a specific cross-reference.
|
||||
*
|
||||
* _Note:_ You should not resolve any cross-references in this service method. Cross-reference
|
||||
* resolution depends on the scope computation phase to be completed.
|
||||
*
|
||||
* @param document The document for which to compute its local symbols.
|
||||
* @param cancelToken Indicates when to cancel the current operation.
|
||||
* @throws `OperationCanceled` if a user action occurs during execution
|
||||
*/
|
||||
collectLocalSymbols(document: LangiumDocument, cancelToken?: CancellationToken): Promise<LocalSymbols>;
|
||||
}
|
||||
/**
|
||||
* The default scope computation creates and collects 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 that are to be
|
||||
* included in the local scope of their particular container nodes. They are collected in a `DocumentSymbols` table.
|
||||
* 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 declare class DefaultScopeComputation implements ScopeComputation {
|
||||
protected readonly nameProvider: NameProvider;
|
||||
protected readonly descriptions: AstNodeDescriptionProvider;
|
||||
constructor(services: LangiumCoreServices);
|
||||
collectExportedSymbols(document: LangiumDocument, cancelToken?: CancellationToken): Promise<AstNodeDescription[]>;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
collectExportedSymbolsForNode(parentNode: AstNode, document: LangiumDocument<AstNode>, children?: (root: AstNode) => Iterable<AstNode>, cancelToken?: CancellationToken): Promise<AstNodeDescription[]>;
|
||||
/**
|
||||
* Adds 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.
|
||||
*/
|
||||
protected addExportedSymbol(node: AstNode, exports: AstNodeDescription[], document: LangiumDocument): void;
|
||||
collectLocalSymbols(document: LangiumDocument, cancelToken?: CancellationToken): Promise<LocalSymbols>;
|
||||
/**
|
||||
* Adds a single node to the local symbols of its containing document if it has a name.
|
||||
* The default implementation makes the node visible in the subtree of its container if it does have a container.
|
||||
* Override this method to change this, e.g. by increasing the visibility to a higher level in the AST.
|
||||
*/
|
||||
protected addLocalSymbol(node: AstNode, document: LangiumDocument, symbols: MultiMap<AstNode, AstNodeDescription>): void;
|
||||
}
|
||||
//# sourceMappingURL=scope-computation.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scope-computation.d.ts","sourceRoot":"","sources":["../../src/references/scope-computation.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAE7B;;;;;;;;;;;;OAYG;IACH,sBAAsB,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAElH;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1G;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,uBAAwB,YAAW,gBAAgB;IAE5D,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;gBAEhD,QAAQ,EAAE,mBAAmB;IAKnC,sBAAsB,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,oBAAyB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAI5H;;;;;;;;;;;OAWG;IACG,6BAA6B,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAE,CAAC,IAAI,EAAE,OAAO,KAAK,QAAQ,CAAC,OAAO,CAAkB,EAAE,WAAW,GAAE,iBAA0C,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAWrP;;;OAGG;IACH,SAAS,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI;IASpG,mBAAmB,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,oBAAyB,GAAG,OAAO,CAAC,YAAY,CAAC;IAWjH;;;;OAIG;IACH,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,GAAG,IAAI;CAU3H"}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/******************************************************************************
|
||||
* 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 { streamAllContents, streamContents } from '../utils/ast-utils.js';
|
||||
import { CancellationToken } from '../utils/cancellation.js';
|
||||
import { MultiMap } from '../utils/collections.js';
|
||||
import { interruptAndCheck } from '../utils/promise-utils.js';
|
||||
/**
|
||||
* The default scope computation creates and collects 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 that are to be
|
||||
* included in the local scope of their particular container nodes. They are collected in a `DocumentSymbols` table.
|
||||
* 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 collectExportedSymbols(document, cancelToken = CancellationToken.None) {
|
||||
return this.collectExportedSymbolsForNode(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 collectExportedSymbolsForNode(parentNode, document, children = streamContents, cancelToken = CancellationToken.None) {
|
||||
const exports = [];
|
||||
this.addExportedSymbol(parentNode, exports, document);
|
||||
for (const node of children(parentNode)) {
|
||||
await interruptAndCheck(cancelToken);
|
||||
this.addExportedSymbol(node, exports, document);
|
||||
}
|
||||
return exports;
|
||||
}
|
||||
/**
|
||||
* Adds 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.
|
||||
*/
|
||||
addExportedSymbol(node, exports, document) {
|
||||
const name = this.nameProvider.getName(node);
|
||||
if (name) {
|
||||
exports.push(this.descriptions.createDescription(node, name, document));
|
||||
}
|
||||
}
|
||||
// --- local symbols gathering ---
|
||||
async collectLocalSymbols(document, cancelToken = CancellationToken.None) {
|
||||
const rootNode = document.parseResult.value;
|
||||
const symbols = 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.addLocalSymbol(node, document, symbols);
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
/**
|
||||
* Adds a single node to the local symbols of its containing document if it has a name.
|
||||
* The default implementation makes the node visible in the subtree of its container if it does have a container.
|
||||
* Override this method to change this, e.g. by increasing the visibility to a higher level in the AST.
|
||||
*/
|
||||
addLocalSymbol(node, document, symbols) {
|
||||
const container = node.$container;
|
||||
if (container) {
|
||||
const name = this.nameProvider.getName(node);
|
||||
if (name) {
|
||||
symbols.add(container, this.descriptions.createDescription(node, name, document));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=scope-computation.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scope-computation.js","sourceRoot":"","sources":["../../src/references/scope-computation.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AA2C9D;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,uBAAuB;IAKhC,YAAY,QAA6B;QACrC,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC;QACrD,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC,SAAS,CAAC,0BAA0B,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,QAAyB,EAAE,WAAW,GAAG,iBAAiB,CAAC,IAAI;QACxF,OAAO,IAAI,CAAC,6BAA6B,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC5G,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,6BAA6B,CAAC,UAAmB,EAAE,QAAkC,EAAE,WAAiD,cAAc,EAAE,cAAiC,iBAAiB,CAAC,IAAI;QACjN,MAAM,OAAO,GAAyB,EAAE,CAAC;QAEzC,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACtD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACtC,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACrC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;;OAGG;IACO,iBAAiB,CAAC,IAAa,EAAE,OAA6B,EAAE,QAAyB;QAC/F,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,IAAI,EAAE,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC5E,CAAC;IACL,CAAC;IAED,kCAAkC;IAElC,KAAK,CAAC,mBAAmB,CAAC,QAAyB,EAAE,WAAW,GAAG,iBAAiB,CAAC,IAAI;QACrF,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,QAAQ,EAA+B,CAAC;QAC5D,wFAAwF;QACxF,KAAK,MAAM,IAAI,IAAI,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7C,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;YACrC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACO,cAAc,CAAC,IAAa,EAAE,QAAyB,EAAE,OAA8C;QAC7G,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,SAAS,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,IAAI,EAAE,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;YACtF,CAAC;QACL,CAAC;IACL,CAAC;CAEJ"}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/******************************************************************************
|
||||
* 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 type { LangiumCoreServices } from '../services.js';
|
||||
import type { AstNode, AstNodeDescription, AstReflection, ReferenceInfo } from '../syntax-tree.js';
|
||||
import type { AstNodeDescriptionProvider } from '../workspace/ast-descriptions.js';
|
||||
import type { IndexManager } from '../workspace/index-manager.js';
|
||||
import type { NameProvider } from './name-provider.js';
|
||||
import type { Scope, ScopeOptions } from './scope.js';
|
||||
import { WorkspaceCache } from '../utils/caching.js';
|
||||
/**
|
||||
* Language-specific service for determining the scope of target elements visible in a specific cross-reference context.
|
||||
*/
|
||||
export interface ScopeProvider {
|
||||
/**
|
||||
* Return a scope describing what elements are visible for the given AST node and cross-reference
|
||||
* identifier.
|
||||
*
|
||||
* @param context Information about the reference for which a scope is requested.
|
||||
*/
|
||||
getScope(context: ReferenceInfo): Scope;
|
||||
}
|
||||
export declare class DefaultScopeProvider implements ScopeProvider {
|
||||
protected readonly reflection: AstReflection;
|
||||
protected readonly nameProvider: NameProvider;
|
||||
protected readonly descriptions: AstNodeDescriptionProvider;
|
||||
protected readonly indexManager: IndexManager;
|
||||
protected readonly globalScopeCache: WorkspaceCache<string, Scope>;
|
||||
constructor(services: LangiumCoreServices);
|
||||
getScope(context: ReferenceInfo): Scope;
|
||||
/**
|
||||
* Create a scope for the given collection of AST node descriptions.
|
||||
*/
|
||||
protected createScope(elements: Iterable<AstNodeDescription>, outerScope?: Scope, options?: ScopeOptions): Scope;
|
||||
/**
|
||||
* Create a scope for the given collection of AST nodes, which need to be transformed into respective
|
||||
* descriptions first. This is done using the `NameProvider` and `AstNodeDescriptionProvider` services.
|
||||
*/
|
||||
protected createScopeForNodes(elements: Iterable<AstNode>, outerScope?: Scope, options?: ScopeOptions): Scope;
|
||||
/**
|
||||
* Create a global scope filtered for the given reference type.
|
||||
*/
|
||||
protected getGlobalScope(referenceType: string, _context: ReferenceInfo): Scope;
|
||||
}
|
||||
//# sourceMappingURL=scope-provider.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scope-provider.d.ts","sourceRoot":"","sources":["../../src/references/scope-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEnG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAC,MAAM,YAAY,CAAC;AAIrD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,aAAa;IAE1B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,KAAK,CAAC;CAE3C;AAED,qBAAa,oBAAqB,YAAW,aAAa;IAEtD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAC5D,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAE9C,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;gBAEvD,QAAQ,EAAE,mBAAmB;IAQzC,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,KAAK;IAuBvC;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK;IAIhH;;;OAGG;IACH,SAAS,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,KAAK;IAW7G;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,KAAK;CAIlF"}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* 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 { MultiMapScope, StreamScope } from './scope.js';
|
||||
import { getDocument } from '../utils/ast-utils.js';
|
||||
import { stream } from '../utils/stream.js';
|
||||
import { WorkspaceCache } from '../utils/caching.js';
|
||||
export class DefaultScopeProvider {
|
||||
constructor(services) {
|
||||
this.reflection = services.shared.AstReflection;
|
||||
this.nameProvider = services.references.NameProvider;
|
||||
this.descriptions = services.workspace.AstNodeDescriptionProvider;
|
||||
this.indexManager = services.shared.workspace.IndexManager;
|
||||
this.globalScopeCache = new WorkspaceCache(services.shared);
|
||||
}
|
||||
getScope(context) {
|
||||
const scopes = [];
|
||||
const referenceType = this.reflection.getReferenceType(context);
|
||||
const localSymbols = getDocument(context.container).localSymbols;
|
||||
if (localSymbols) {
|
||||
let currentNode = context.container;
|
||||
do {
|
||||
if (localSymbols.has(currentNode)) {
|
||||
scopes.push(localSymbols.getStream(currentNode).filter(desc => this.reflection.isSubtype(desc.type, referenceType)));
|
||||
}
|
||||
currentNode = currentNode.$container;
|
||||
} while (currentNode);
|
||||
}
|
||||
let result = this.getGlobalScope(referenceType, context);
|
||||
for (let i = scopes.length - 1; i >= 0; i--) {
|
||||
result = this.createScope(scopes[i], result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Create a scope for the given collection of AST node descriptions.
|
||||
*/
|
||||
createScope(elements, outerScope, options) {
|
||||
return new StreamScope(stream(elements), outerScope, options);
|
||||
}
|
||||
/**
|
||||
* Create a scope for the given collection of AST nodes, which need to be transformed into respective
|
||||
* descriptions first. This is done using the `NameProvider` and `AstNodeDescriptionProvider` services.
|
||||
*/
|
||||
createScopeForNodes(elements, outerScope, options) {
|
||||
const s = stream(elements).map(e => {
|
||||
const name = this.nameProvider.getName(e);
|
||||
if (name) {
|
||||
return this.descriptions.createDescription(e, name);
|
||||
}
|
||||
return undefined;
|
||||
}).nonNullable();
|
||||
return new StreamScope(s, outerScope, options);
|
||||
}
|
||||
/**
|
||||
* Create a global scope filtered for the given reference type.
|
||||
*/
|
||||
getGlobalScope(referenceType, _context) {
|
||||
return this.globalScopeCache.get(referenceType, () => new MultiMapScope(this.indexManager.allElements(referenceType)));
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=scope-provider.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scope-provider.js","sourceRoot":"","sources":["../../src/references/scope-provider.ts"],"names":[],"mappings":"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"}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2023 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 type { AstNodeDescription } from '../syntax-tree.js';
|
||||
import { MultiMap } from '../utils/collections.js';
|
||||
import type { Stream } from '../utils/stream.js';
|
||||
/**
|
||||
* A scope describes what target elements are visible from a specific cross-reference context.
|
||||
*/
|
||||
export interface Scope {
|
||||
/**
|
||||
* Find a target element matching the given name. If no element is found, `undefined` is returned.
|
||||
* If multiple matching elements are present, the selection of the returned element should be done
|
||||
* according to the semantics of your language. Usually it is the element that is most closely defined.
|
||||
*
|
||||
* @param name Name of the cross-reference target as it appears in the source text.
|
||||
*/
|
||||
getElement(name: string): AstNodeDescription | undefined;
|
||||
/**
|
||||
* Finds all target elements matching the given name. If no element is found, an empty stream is returned.
|
||||
*
|
||||
* @param name Name of the cross-reference target as it appears in the source text.
|
||||
*/
|
||||
getElements(name: string): Stream<AstNodeDescription>;
|
||||
/**
|
||||
* Create a stream of all elements in the scope. This is used to compute completion proposals to be
|
||||
* shown in the editor.
|
||||
*/
|
||||
getAllElements(): Stream<AstNodeDescription>;
|
||||
}
|
||||
export interface ScopeOptions {
|
||||
/**
|
||||
* Whether the scope should be case insensitive.
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
caseInsensitive?: boolean;
|
||||
/**
|
||||
* Whether the outer scope should be concatenated with the local scope when calling `getElements`.
|
||||
* Defaults to `true`.
|
||||
*/
|
||||
concatOuterScope?: boolean;
|
||||
}
|
||||
/**
|
||||
* The default scope implementation is based on a `Stream`. It has an optional _outer scope_ describing
|
||||
* the next level of elements, which are queried when a target element is not found in the stream provided
|
||||
* to this scope.
|
||||
*/
|
||||
export declare class StreamScope implements Scope {
|
||||
readonly elements: Stream<AstNodeDescription>;
|
||||
readonly outerScope?: Scope;
|
||||
readonly caseInsensitive: boolean;
|
||||
readonly concatOuterScope: boolean;
|
||||
constructor(elements: Stream<AstNodeDescription>, outerScope?: Scope, options?: ScopeOptions);
|
||||
getAllElements(): Stream<AstNodeDescription>;
|
||||
getElement(name: string): AstNodeDescription | undefined;
|
||||
getElements(name: string): Stream<AstNodeDescription>;
|
||||
}
|
||||
export declare class MapScope implements Scope {
|
||||
readonly elements: Map<string, AstNodeDescription>;
|
||||
readonly outerScope?: Scope;
|
||||
readonly caseInsensitive: boolean;
|
||||
readonly concatOuterScope: boolean;
|
||||
constructor(elements: Iterable<AstNodeDescription>, outerScope?: Scope, options?: ScopeOptions);
|
||||
getElement(name: string): AstNodeDescription | undefined;
|
||||
getElements(name: string): Stream<AstNodeDescription>;
|
||||
getAllElements(): Stream<AstNodeDescription>;
|
||||
}
|
||||
export declare class MultiMapScope implements Scope {
|
||||
readonly elements: MultiMap<string, AstNodeDescription>;
|
||||
readonly outerScope?: Scope;
|
||||
readonly caseInsensitive: boolean;
|
||||
readonly concatOuterScope: boolean;
|
||||
constructor(elements: Iterable<AstNodeDescription>, outerScope?: Scope, options?: ScopeOptions);
|
||||
getElement(name: string): AstNodeDescription | undefined;
|
||||
getElements(name: string): Stream<AstNodeDescription>;
|
||||
getAllElements(): Stream<AstNodeDescription>;
|
||||
}
|
||||
export declare const EMPTY_SCOPE: Scope;
|
||||
//# sourceMappingURL=scope.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/references/scope.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGjD;;GAEG;AACH,MAAM,WAAW,KAAK;IAElB;;;;;;OAMG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAAC;IAEzD;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAEtD;;;OAGG;IACH,cAAc,IAAI,MAAM,CAAC,kBAAkB,CAAC,CAAC;CAEhD;AAED,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;GAIG;AACH,qBAAa,WAAY,YAAW,KAAK;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;gBAEvB,QAAQ,EAAE,MAAM,CAAC,kBAAkB,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,YAAY;IAO5F,cAAc,IAAI,MAAM,CAAC,kBAAkB,CAAC;IAQ5C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAcxD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC;CAWxD;AAED,qBAAa,QAAS,YAAW,KAAK;IAClC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;gBAEvB,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,YAAY;IAa9F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAYxD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAWrD,cAAc,IAAI,MAAM,CAAC,kBAAkB,CAAC;CAQ/C;AAED,qBAAa,aAAc,YAAW,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;gBAEvB,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,YAAY;IAa9F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAYxD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAUrD,cAAc,IAAI,MAAM,CAAC,kBAAkB,CAAC;CAQ/C;AAED,eAAO,MAAM,WAAW,EAAE,KAUzB,CAAC"}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2023 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 { MultiMap } from '../utils/collections.js';
|
||||
import { EMPTY_STREAM, stream } from '../utils/stream.js';
|
||||
/**
|
||||
* The default scope implementation is based on a `Stream`. It has an optional _outer scope_ describing
|
||||
* the next level of elements, which are queried when a target element is not found in the stream provided
|
||||
* to this scope.
|
||||
*/
|
||||
export class StreamScope {
|
||||
constructor(elements, outerScope, options) {
|
||||
this.elements = elements;
|
||||
this.outerScope = outerScope;
|
||||
this.caseInsensitive = options?.caseInsensitive ?? false;
|
||||
this.concatOuterScope = options?.concatOuterScope ?? true;
|
||||
}
|
||||
getAllElements() {
|
||||
if (this.outerScope) {
|
||||
return this.elements.concat(this.outerScope.getAllElements());
|
||||
}
|
||||
else {
|
||||
return this.elements;
|
||||
}
|
||||
}
|
||||
getElement(name) {
|
||||
const lowerCaseName = this.caseInsensitive ? name.toLowerCase() : name;
|
||||
const local = this.caseInsensitive
|
||||
? this.elements.find(e => e.name.toLowerCase() === lowerCaseName)
|
||||
: this.elements.find(e => e.name === name);
|
||||
if (local) {
|
||||
return local;
|
||||
}
|
||||
if (this.outerScope) {
|
||||
return this.outerScope.getElement(name);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
getElements(name) {
|
||||
const lowerCaseName = this.caseInsensitive ? name.toLowerCase() : name;
|
||||
const local = this.caseInsensitive
|
||||
? this.elements.filter(e => e.name.toLowerCase() === lowerCaseName)
|
||||
: this.elements.filter(e => e.name === name);
|
||||
if ((this.concatOuterScope || local.isEmpty()) && this.outerScope) {
|
||||
return local.concat(this.outerScope.getElements(name));
|
||||
}
|
||||
else {
|
||||
return local;
|
||||
}
|
||||
}
|
||||
}
|
||||
export class MapScope {
|
||||
constructor(elements, outerScope, options) {
|
||||
this.elements = new Map();
|
||||
this.caseInsensitive = options?.caseInsensitive ?? false;
|
||||
this.concatOuterScope = options?.concatOuterScope ?? true;
|
||||
for (const element of elements) {
|
||||
const name = this.caseInsensitive
|
||||
? element.name.toLowerCase()
|
||||
: element.name;
|
||||
this.elements.set(name, element);
|
||||
}
|
||||
this.outerScope = outerScope;
|
||||
}
|
||||
getElement(name) {
|
||||
const localName = this.caseInsensitive ? name.toLowerCase() : name;
|
||||
const local = this.elements.get(localName);
|
||||
if (local) {
|
||||
return local;
|
||||
}
|
||||
if (this.outerScope) {
|
||||
return this.outerScope.getElement(name);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
getElements(name) {
|
||||
const localName = this.caseInsensitive ? name.toLowerCase() : name;
|
||||
const local = this.elements.get(localName);
|
||||
const arr = local ? [local] : [];
|
||||
if ((this.concatOuterScope || arr.length > 0) && this.outerScope) {
|
||||
return stream(arr).concat(this.outerScope.getElements(name));
|
||||
}
|
||||
else {
|
||||
return stream(arr);
|
||||
}
|
||||
}
|
||||
getAllElements() {
|
||||
let elementStream = stream(this.elements.values());
|
||||
if (this.outerScope) {
|
||||
elementStream = elementStream.concat(this.outerScope.getAllElements());
|
||||
}
|
||||
return elementStream;
|
||||
}
|
||||
}
|
||||
export class MultiMapScope {
|
||||
constructor(elements, outerScope, options) {
|
||||
this.elements = new MultiMap();
|
||||
this.caseInsensitive = options?.caseInsensitive ?? false;
|
||||
this.concatOuterScope = options?.concatOuterScope ?? true;
|
||||
for (const element of elements) {
|
||||
const name = this.caseInsensitive
|
||||
? element.name.toLowerCase()
|
||||
: element.name;
|
||||
this.elements.add(name, element);
|
||||
}
|
||||
this.outerScope = outerScope;
|
||||
}
|
||||
getElement(name) {
|
||||
const localName = this.caseInsensitive ? name.toLowerCase() : name;
|
||||
const local = this.elements.get(localName)[0];
|
||||
if (local) {
|
||||
return local;
|
||||
}
|
||||
if (this.outerScope) {
|
||||
return this.outerScope.getElement(name);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
getElements(name) {
|
||||
const localName = this.caseInsensitive ? name.toLowerCase() : name;
|
||||
const local = this.elements.get(localName);
|
||||
if ((this.concatOuterScope || local.length === 0) && this.outerScope) {
|
||||
return stream(local).concat(this.outerScope.getElements(name));
|
||||
}
|
||||
else {
|
||||
return stream(local);
|
||||
}
|
||||
}
|
||||
getAllElements() {
|
||||
let elementStream = stream(this.elements.values());
|
||||
if (this.outerScope) {
|
||||
elementStream = elementStream.concat(this.outerScope.getAllElements());
|
||||
}
|
||||
return elementStream;
|
||||
}
|
||||
}
|
||||
export const EMPTY_SCOPE = {
|
||||
getElement() {
|
||||
return undefined;
|
||||
},
|
||||
getElements() {
|
||||
return EMPTY_STREAM;
|
||||
},
|
||||
getAllElements() {
|
||||
return EMPTY_STREAM;
|
||||
}
|
||||
};
|
||||
//# sourceMappingURL=scope.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user