完成世界书、骰子、apiconfig页面处理
This commit is contained in:
74
frontend/node_modules/langium/lib/workspace/ast-descriptions.d.ts
generated
vendored
Normal file
74
frontend/node_modules/langium/lib/workspace/ast-descriptions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/******************************************************************************
|
||||
* 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 { URI } from '../utils/uri-utils.js';
|
||||
import type { NameProvider } from '../references/name-provider.js';
|
||||
import type { LangiumCoreServices } from '../services.js';
|
||||
import type { AstNode, AstNodeDescription, ReferenceInfo } from '../syntax-tree.js';
|
||||
import type { AstNodeLocator } from './ast-node-locator.js';
|
||||
import type { DocumentSegment, LangiumDocument } from './documents.js';
|
||||
import { CancellationToken } from '../utils/cancellation.js';
|
||||
/**
|
||||
* Language-specific service for creating descriptions of AST nodes to be used for cross-reference resolutions.
|
||||
*/
|
||||
export interface AstNodeDescriptionProvider {
|
||||
/**
|
||||
* Create a description for the given AST node. This service method is typically used while indexing
|
||||
* the contents of a document and during scope computation.
|
||||
*
|
||||
* @param node An AST node.
|
||||
* @param name The name to be used to refer to the AST node. By default, this is determined by the
|
||||
* `NameProvider` service, but alternative names may be provided according to the semantics
|
||||
* of your language.
|
||||
* @param document The document containing the AST node. If omitted, it is taken from the root AST node.
|
||||
*/
|
||||
createDescription(node: AstNode, name: string | undefined, document?: LangiumDocument): AstNodeDescription;
|
||||
}
|
||||
export declare class DefaultAstNodeDescriptionProvider implements AstNodeDescriptionProvider {
|
||||
protected readonly astNodeLocator: AstNodeLocator;
|
||||
protected readonly nameProvider: NameProvider;
|
||||
constructor(services: LangiumCoreServices);
|
||||
createDescription(node: AstNode, name: string | undefined, document?: LangiumDocument): AstNodeDescription;
|
||||
}
|
||||
/**
|
||||
* Describes a cross-reference within a document or between two documents.
|
||||
*/
|
||||
export interface ReferenceDescription {
|
||||
/** URI of the document that holds a reference */
|
||||
sourceUri: URI;
|
||||
/** Path to AstNode that holds a reference */
|
||||
sourcePath: string;
|
||||
/** Target document uri */
|
||||
targetUri: URI;
|
||||
/** Path to the target AstNode inside the document */
|
||||
targetPath: string;
|
||||
/** Segment of the reference text. */
|
||||
segment: DocumentSegment;
|
||||
/** Marks a local reference i.e. a cross reference inside a document. */
|
||||
local?: boolean;
|
||||
}
|
||||
/**
|
||||
* Language-specific service to create descriptions of all cross-references in a document. These are used by the `IndexManager`
|
||||
* to determine which documents are affected and should be rebuilt when a document is changed.
|
||||
*/
|
||||
export interface ReferenceDescriptionProvider {
|
||||
/**
|
||||
* Create descriptions of all cross-references found in the given document. These descriptions are
|
||||
* gathered by the `IndexManager` and stored in the global index so they can be considered when
|
||||
* a document change is reported by the client.
|
||||
*
|
||||
* @param document The document in which to gather cross-references.
|
||||
* @param cancelToken Indicates when to cancel the current operation.
|
||||
* @throws `OperationCanceled` if a user action occurs during execution
|
||||
*/
|
||||
createDescriptions(document: LangiumDocument, cancelToken?: CancellationToken): Promise<ReferenceDescription[]>;
|
||||
}
|
||||
export declare class DefaultReferenceDescriptionProvider implements ReferenceDescriptionProvider {
|
||||
protected readonly nodeLocator: AstNodeLocator;
|
||||
constructor(services: LangiumCoreServices);
|
||||
createDescriptions(document: LangiumDocument, cancelToken?: CancellationToken): Promise<ReferenceDescription[]>;
|
||||
protected createInfoDescriptions(refInfo: ReferenceInfo): ReferenceDescription[];
|
||||
}
|
||||
//# sourceMappingURL=ast-descriptions.d.ts.map
|
||||
1
frontend/node_modules/langium/lib/workspace/ast-descriptions.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/workspace/ast-descriptions.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ast-descriptions.js","sourceRoot":"","sources":["../../src/workspace/ast-descriptions.ts"],"names":[],"mappings":"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"}
|
||||
46
frontend/node_modules/langium/lib/workspace/ast-node-locator.js
generated
vendored
Normal file
46
frontend/node_modules/langium/lib/workspace/ast-node-locator.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
export class DefaultAstNodeLocator {
|
||||
constructor() {
|
||||
this.segmentSeparator = '/';
|
||||
this.indexSeparator = '@';
|
||||
}
|
||||
getAstNodePath(node) {
|
||||
if (node.$container) {
|
||||
const containerPath = this.getAstNodePath(node.$container);
|
||||
const newSegment = this.getPathSegment(node);
|
||||
const nodePath = containerPath + this.segmentSeparator + newSegment;
|
||||
return nodePath;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
getPathSegment({ $containerProperty, $containerIndex }) {
|
||||
if (!$containerProperty) {
|
||||
throw new Error("Missing '$containerProperty' in AST node.");
|
||||
}
|
||||
if ($containerIndex !== undefined) {
|
||||
return $containerProperty + this.indexSeparator + $containerIndex;
|
||||
}
|
||||
return $containerProperty;
|
||||
}
|
||||
getAstNode(node, path) {
|
||||
const segments = path.split(this.segmentSeparator);
|
||||
return segments.reduce((previousValue, currentValue) => {
|
||||
if (!previousValue || currentValue.length === 0) {
|
||||
return previousValue;
|
||||
}
|
||||
const propertyIndex = currentValue.indexOf(this.indexSeparator);
|
||||
if (propertyIndex > 0) {
|
||||
const property = currentValue.substring(0, propertyIndex);
|
||||
const arrayIndex = parseInt(currentValue.substring(propertyIndex + 1));
|
||||
const array = previousValue[property];
|
||||
return array?.[arrayIndex];
|
||||
}
|
||||
return previousValue[currentValue];
|
||||
}, node);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ast-node-locator.js.map
|
||||
282
frontend/node_modules/langium/lib/workspace/documents.d.ts
generated
vendored
Normal file
282
frontend/node_modules/langium/lib/workspace/documents.d.ts
generated
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
/**
|
||||
* Re-export 'TextDocument' from 'vscode-languageserver-textdocument' for convenience,
|
||||
* including both type _and_ symbol (namespace), as we here and there also refer to the symbol,
|
||||
* the overhead is very small, just a few kilobytes.
|
||||
* Everything else of that package (at the time contributing) is also defined
|
||||
* in 'vscode-languageserver-protocol' or 'vscode-languageserver-types'.
|
||||
*/
|
||||
export { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import type { Diagnostic, Range } from 'vscode-languageserver-types';
|
||||
import type { FileSystemProvider } from './file-system-provider.js';
|
||||
import type { ParseResult, ParserOptions } from '../parser/langium-parser.js';
|
||||
import type { ServiceRegistry } from '../service-registry.js';
|
||||
import type { LangiumSharedCoreServices } from '../services.js';
|
||||
import type { AstNode, AstNodeDescription, MultiReference, Mutable, Reference } from '../syntax-tree.js';
|
||||
import type { Stream } from '../utils/stream.js';
|
||||
import { TextDocument } from './documents.js';
|
||||
import { CancellationToken } from '../utils/cancellation.js';
|
||||
import { URI, UriTrie } from '../utils/uri-utils.js';
|
||||
/**
|
||||
* A Langium document holds the parse result (AST and CST) and any additional state that is derived
|
||||
* from the AST, e.g. the result of scope precomputation.
|
||||
*/
|
||||
export interface LangiumDocument<T extends AstNode = AstNode> {
|
||||
/** The Uniform Resource Identifier (URI) of the document */
|
||||
readonly uri: URI;
|
||||
/** The text document used to convert between offsets and positions */
|
||||
readonly textDocument: TextDocument;
|
||||
/** The current state of the document */
|
||||
state: DocumentState;
|
||||
/** The parse result holds the Abstract Syntax Tree (AST) and potentially also parser / lexer errors */
|
||||
parseResult: ParseResult<T>;
|
||||
/** Result of the scope precomputation phase */
|
||||
localSymbols?: LocalSymbols;
|
||||
/** An array of all cross-references found in the AST while linking */
|
||||
references: Array<Reference | MultiReference>;
|
||||
/** Result of the validation phase */
|
||||
diagnostics?: Diagnostic[];
|
||||
}
|
||||
/**
|
||||
* A document is subject to several phases that are run in predefined order. Any state value implies that
|
||||
* smaller state values are finished as well.
|
||||
*/
|
||||
export declare enum DocumentState {
|
||||
/**
|
||||
* The text content has changed and needs to be parsed again. The AST held by this outdated
|
||||
* document instance is no longer valid.
|
||||
*/
|
||||
Changed = 0,
|
||||
/**
|
||||
* An AST has been created from the text content. The document structure can be traversed,
|
||||
* but cross-references cannot be resolved yet. If necessary, the structure can be manipulated
|
||||
* at this stage as a preprocessing step.
|
||||
*/
|
||||
Parsed = 1,
|
||||
/**
|
||||
* The `IndexManager` service has processed AST nodes of this document. This means the
|
||||
* exported symbols are available in the global scope and can be resolved from other documents.
|
||||
*/
|
||||
IndexedContent = 2,
|
||||
/**
|
||||
* The `ScopeComputation` service has processed this document. This means the document's locally accessible
|
||||
* symbols are captured in a `DocumentSymbols` table and can be looked up by the `ScopeProvider` service.
|
||||
* Once a document has reached this state, you may follow every reference - it will lazily
|
||||
* resolve its `ref` property and yield either the target AST node or `undefined` in case
|
||||
* the target is not in scope.
|
||||
*/
|
||||
ComputedScopes = 3,
|
||||
/**
|
||||
* The `Linker` service has processed this document. All outgoing references have been
|
||||
* resolved or marked as erroneous.
|
||||
*/
|
||||
Linked = 4,
|
||||
/**
|
||||
* The `IndexManager` service has processed AST node references of this document. This is
|
||||
* necessary to determine which documents are affected by a change in one of the workspace
|
||||
* documents.
|
||||
*/
|
||||
IndexedReferences = 5,
|
||||
/**
|
||||
* The `DocumentValidator` service has processed this document. The language server listens
|
||||
* to the results of this phase and sends diagnostics to the client.
|
||||
*/
|
||||
Validated = 6
|
||||
}
|
||||
/**
|
||||
* Result of the scope pre-computation phase performed by the `ScopeComputation` service.
|
||||
* It maps AST nodes of a document to their corresponding sets of symbols that are accessible
|
||||
* by those nodes/subtrees, provided any symbols corresponding specifically to those nodes/subtrees exist.
|
||||
* The sets of symbols are assumed to be un-ordered. Hence, no assumptions about the order of
|
||||
* symbols in the sets should be made. The default `ScopeComputation` implementation uses an
|
||||
* instance of `MultiMap<AstNode, AstNodeDescription>`, which conforms to this interface.
|
||||
*/
|
||||
export interface LocalSymbols {
|
||||
has(node: AstNode): boolean;
|
||||
getStream(key: AstNode): Stream<AstNodeDescription>;
|
||||
}
|
||||
export interface DocumentSegment {
|
||||
readonly range: Range;
|
||||
readonly offset: number;
|
||||
readonly length: number;
|
||||
readonly end: number;
|
||||
}
|
||||
/**
|
||||
* Surrogate definition of the `TextDocuments` interface from the `vscode-languageserver` package.
|
||||
* No implementation object is expected to be offered by `LangiumCoreServices`, but only by `LangiumLSPServices`.
|
||||
*/
|
||||
export type TextDocumentProvider = {
|
||||
get(uri: string | URI): TextDocument | undefined;
|
||||
};
|
||||
/**
|
||||
* Shared service for creating `LangiumDocument` instances.
|
||||
*
|
||||
* Register a custom implementation if special (additional) behavior is required for your language(s).
|
||||
* Note: If you specialize {@link fromString} or {@link fromTextDocument} you probably might want to
|
||||
* specialize {@link update}, too!
|
||||
*/
|
||||
export interface LangiumDocumentFactory {
|
||||
/**
|
||||
* Create a Langium document from a `TextDocument` (usually associated with a file).
|
||||
*/
|
||||
fromTextDocument<T extends AstNode = AstNode>(textDocument: TextDocument, uri?: URI, options?: ParserOptions): LangiumDocument<T>;
|
||||
/**
|
||||
* Create a Langium document from a `TextDocument` asynchronously. This action can be cancelled if a cancellable parser implementation has been provided.
|
||||
*/
|
||||
fromTextDocument<T extends AstNode = AstNode>(textDocument: TextDocument, uri: URI | undefined, cancellationToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
/**
|
||||
* Create an Langium document from an in-memory string.
|
||||
*/
|
||||
fromString<T extends AstNode = AstNode>(text: string, uri: URI, options?: ParserOptions): LangiumDocument<T>;
|
||||
/**
|
||||
* Create a Langium document from an in-memory string asynchronously. This action can be cancelled if a cancellable parser implementation has been provided.
|
||||
*/
|
||||
fromString<T extends AstNode = AstNode>(text: string, uri: URI, cancellationToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
/**
|
||||
* Create an Langium document from a model that has been constructed in memory.
|
||||
*/
|
||||
fromModel<T extends AstNode = AstNode>(model: T, uri: URI): LangiumDocument<T>;
|
||||
/**
|
||||
* Create an Langium document from a specified `URI`. The factory will use the `FileSystemAccess` service to read the file.
|
||||
*/
|
||||
fromUri<T extends AstNode = AstNode>(uri: URI, cancellationToken?: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
/**
|
||||
* Update the given document after changes in the corresponding textual representation.
|
||||
* Method is called by the document builder after it has been requested to build an existing
|
||||
* document and the document's state is {@link DocumentState.Changed}.
|
||||
* The text parsing is expected to be done the same way as in {@link fromTextDocument}
|
||||
* and {@link fromString}.
|
||||
*/
|
||||
update<T extends AstNode = AstNode>(document: LangiumDocument<T>, cancellationToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
}
|
||||
export declare class DefaultLangiumDocumentFactory implements LangiumDocumentFactory {
|
||||
protected readonly serviceRegistry: ServiceRegistry;
|
||||
protected readonly textDocuments?: TextDocumentProvider;
|
||||
protected readonly fileSystemProvider: FileSystemProvider;
|
||||
constructor(services: LangiumSharedCoreServices);
|
||||
fromUri<T extends AstNode = AstNode>(uri: URI, cancellationToken?: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
fromTextDocument<T extends AstNode = AstNode>(textDocument: TextDocument, uri?: URI, options?: ParserOptions): LangiumDocument<T>;
|
||||
fromTextDocument<T extends AstNode = AstNode>(textDocument: TextDocument, uri: URI | undefined, cancellationToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
fromString<T extends AstNode = AstNode>(text: string, uri: URI, options?: ParserOptions): LangiumDocument<T>;
|
||||
fromString<T extends AstNode = AstNode>(text: string, uri: URI, cancellationToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
fromModel<T extends AstNode = AstNode>(model: T, uri: URI): LangiumDocument<T>;
|
||||
protected create<T extends AstNode = AstNode>(uri: URI, content: string | TextDocument | {
|
||||
$model: T;
|
||||
}, options?: ParserOptions): LangiumDocument<T>;
|
||||
protected createAsync<T extends AstNode = AstNode>(uri: URI, content: string | TextDocument, cancelToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
/**
|
||||
* Create a LangiumDocument from a given parse result.
|
||||
*
|
||||
* A TextDocument is created on demand if it is not provided as argument here. Usually this
|
||||
* should not be necessary because the main purpose of the TextDocument is to convert between
|
||||
* text ranges and offsets, which is done solely in LSP request handling.
|
||||
*
|
||||
* With the introduction of {@link update} below this method is supposed to be mainly called
|
||||
* during workspace initialization and on addition/recognition of new files, while changes in
|
||||
* existing documents are processed via {@link update}.
|
||||
*/
|
||||
protected createLangiumDocument<T extends AstNode = AstNode>(parseResult: ParseResult<T>, uri: URI, textDocument?: TextDocument, text?: string): LangiumDocument<T>;
|
||||
update<T extends AstNode = AstNode>(document: Mutable<LangiumDocument<T>>, cancellationToken: CancellationToken): Promise<LangiumDocument<T>>;
|
||||
protected parse<T extends AstNode>(uri: URI, text: string, options?: ParserOptions): ParseResult<T>;
|
||||
protected parseAsync<T extends AstNode>(uri: URI, text: string, cancellationToken: CancellationToken): Promise<ParseResult<T>>;
|
||||
protected createTextDocumentGetter(uri: URI, text?: string): () => TextDocument;
|
||||
}
|
||||
/**
|
||||
* Shared service for managing Langium documents.
|
||||
*/
|
||||
export interface LangiumDocuments {
|
||||
/**
|
||||
* A stream of all documents managed under this service.
|
||||
*/
|
||||
readonly all: Stream<LangiumDocument>;
|
||||
/**
|
||||
* Manage a new document under this service.
|
||||
* @throws an error if a document with the same URI is already present.
|
||||
*/
|
||||
addDocument(document: LangiumDocument): void;
|
||||
/**
|
||||
* Retrieve the document with the given URI, if present. Otherwise returns `undefined`.
|
||||
*/
|
||||
getDocument(uri: URI): LangiumDocument | undefined;
|
||||
/**
|
||||
* If the given URI is a directory, all documents within this directory are retrieved.
|
||||
* If it is a file, just that single document is retrieved.
|
||||
*/
|
||||
getDocuments(folder: URI): LangiumDocument[];
|
||||
/**
|
||||
* Retrieve the document with the given URI. If not present, a new one will be created using the file system access.
|
||||
* The new document will be added to the list of documents managed under this service.
|
||||
*/
|
||||
getOrCreateDocument(uri: URI, cancellationToken?: CancellationToken): Promise<LangiumDocument>;
|
||||
/**
|
||||
* Creates a new document with the given URI and text content.
|
||||
* The new document is automatically added to this service and can be retrieved using {@link getDocument}.
|
||||
*
|
||||
* @throws an error if a document with the same URI is already present.
|
||||
*/
|
||||
createDocument(uri: URI, text: string): LangiumDocument;
|
||||
/**
|
||||
* Creates a new document with the given URI and text content asynchronously.
|
||||
* The process can be interrupted with a cancellation token.
|
||||
* The new document is automatically added to this service and can be retrieved using {@link getDocument}.
|
||||
*
|
||||
* @throws an error if a document with the same URI is already present.
|
||||
*/
|
||||
createDocument(uri: URI, text: string, cancellationToken: CancellationToken): Promise<LangiumDocument>;
|
||||
/**
|
||||
* Flag the document with the given URI as `Changed`, if present, meaning that its content
|
||||
* is no longer valid. The content (parseResult) stays untouched, while internal data may
|
||||
* be dropped to reduce memory footprint.
|
||||
*
|
||||
* @returns the affected {@link LangiumDocument} if existing for convenience
|
||||
*
|
||||
* @deprecated Since 4.2 use `DocumentBuilder.resetToState(DocumentState.Changed)` instead
|
||||
*/
|
||||
invalidateDocument(uri: URI): LangiumDocument | undefined;
|
||||
/**
|
||||
* Returns `true` if a document with the given URI is managed under this service.
|
||||
*/
|
||||
hasDocument(uri: URI): boolean;
|
||||
/**
|
||||
* Remove the document with the given URI, if present, and mark it as `Changed`, meaning
|
||||
* that its content is no longer valid. The next call to `getOrCreateDocument` with the same
|
||||
* URI will create a new document instance.
|
||||
*
|
||||
* @returns the affected {@link LangiumDocument} if existing for convenience
|
||||
*/
|
||||
deleteDocument(uri: URI): LangiumDocument | undefined;
|
||||
/**
|
||||
* If the given URI is a directory, remove all documents within this directory.
|
||||
* If it is a file, just remove that single document from the documents.
|
||||
*
|
||||
* @returns the affected {@link LangiumDocument}s if existing for convenience
|
||||
*/
|
||||
deleteDocuments(uri: URI): LangiumDocument[];
|
||||
}
|
||||
export declare class DefaultLangiumDocuments implements LangiumDocuments {
|
||||
protected readonly services: LangiumSharedCoreServices;
|
||||
protected readonly langiumDocumentFactory: LangiumDocumentFactory;
|
||||
private documentBuilder;
|
||||
protected readonly documentTrie: UriTrie<LangiumDocument<AstNode>>;
|
||||
constructor(services: LangiumSharedCoreServices);
|
||||
get all(): Stream<LangiumDocument>;
|
||||
addDocument(document: LangiumDocument): void;
|
||||
getDocument(uri: URI): LangiumDocument | undefined;
|
||||
getDocuments(folder: URI): LangiumDocument[];
|
||||
getOrCreateDocument(uri: URI, cancellationToken?: CancellationToken): Promise<LangiumDocument>;
|
||||
createDocument(uri: URI, text: string): LangiumDocument;
|
||||
createDocument(uri: URI, text: string, cancellationToken: CancellationToken): Promise<LangiumDocument>;
|
||||
hasDocument(uri: URI): boolean;
|
||||
/**
|
||||
* @deprecated Since 4.2 use `DocumentBuilder.resetToState(DocumentState.Changed)` instead
|
||||
* TODO remove this for the next major release
|
||||
*/
|
||||
invalidateDocument(uri: URI): LangiumDocument | undefined;
|
||||
deleteDocument(uri: URI): LangiumDocument | undefined;
|
||||
deleteDocuments(folder: URI): LangiumDocument[];
|
||||
}
|
||||
//# sourceMappingURL=documents.d.ts.map
|
||||
278
frontend/node_modules/langium/lib/workspace/documents.js
generated
vendored
Normal file
278
frontend/node_modules/langium/lib/workspace/documents.js
generated
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
/**
|
||||
* Re-export 'TextDocument' from 'vscode-languageserver-textdocument' for convenience,
|
||||
* including both type _and_ symbol (namespace), as we here and there also refer to the symbol,
|
||||
* the overhead is very small, just a few kilobytes.
|
||||
* Everything else of that package (at the time contributing) is also defined
|
||||
* in 'vscode-languageserver-protocol' or 'vscode-languageserver-types'.
|
||||
*/
|
||||
export { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import { TextDocument } from './documents.js';
|
||||
import { CancellationToken } from '../utils/cancellation.js';
|
||||
import { stream } from '../utils/stream.js';
|
||||
import { URI, UriTrie } from '../utils/uri-utils.js';
|
||||
/**
|
||||
* A document is subject to several phases that are run in predefined order. Any state value implies that
|
||||
* smaller state values are finished as well.
|
||||
*/
|
||||
export var DocumentState;
|
||||
(function (DocumentState) {
|
||||
/**
|
||||
* The text content has changed and needs to be parsed again. The AST held by this outdated
|
||||
* document instance is no longer valid.
|
||||
*/
|
||||
DocumentState[DocumentState["Changed"] = 0] = "Changed";
|
||||
/**
|
||||
* An AST has been created from the text content. The document structure can be traversed,
|
||||
* but cross-references cannot be resolved yet. If necessary, the structure can be manipulated
|
||||
* at this stage as a preprocessing step.
|
||||
*/
|
||||
DocumentState[DocumentState["Parsed"] = 1] = "Parsed";
|
||||
/**
|
||||
* The `IndexManager` service has processed AST nodes of this document. This means the
|
||||
* exported symbols are available in the global scope and can be resolved from other documents.
|
||||
*/
|
||||
DocumentState[DocumentState["IndexedContent"] = 2] = "IndexedContent";
|
||||
/**
|
||||
* The `ScopeComputation` service has processed this document. This means the document's locally accessible
|
||||
* symbols are captured in a `DocumentSymbols` table and can be looked up by the `ScopeProvider` service.
|
||||
* Once a document has reached this state, you may follow every reference - it will lazily
|
||||
* resolve its `ref` property and yield either the target AST node or `undefined` in case
|
||||
* the target is not in scope.
|
||||
*/
|
||||
DocumentState[DocumentState["ComputedScopes"] = 3] = "ComputedScopes";
|
||||
/**
|
||||
* The `Linker` service has processed this document. All outgoing references have been
|
||||
* resolved or marked as erroneous.
|
||||
*/
|
||||
DocumentState[DocumentState["Linked"] = 4] = "Linked";
|
||||
/**
|
||||
* The `IndexManager` service has processed AST node references of this document. This is
|
||||
* necessary to determine which documents are affected by a change in one of the workspace
|
||||
* documents.
|
||||
*/
|
||||
DocumentState[DocumentState["IndexedReferences"] = 5] = "IndexedReferences";
|
||||
/**
|
||||
* The `DocumentValidator` service has processed this document. The language server listens
|
||||
* to the results of this phase and sends diagnostics to the client.
|
||||
*/
|
||||
DocumentState[DocumentState["Validated"] = 6] = "Validated";
|
||||
})(DocumentState || (DocumentState = {}));
|
||||
export class DefaultLangiumDocumentFactory {
|
||||
constructor(services) {
|
||||
this.serviceRegistry = services.ServiceRegistry;
|
||||
this.textDocuments = services.workspace.TextDocuments;
|
||||
this.fileSystemProvider = services.workspace.FileSystemProvider;
|
||||
}
|
||||
async fromUri(uri, cancellationToken = CancellationToken.None) {
|
||||
const content = await this.fileSystemProvider.readFile(uri);
|
||||
return this.createAsync(uri, content, cancellationToken);
|
||||
}
|
||||
fromTextDocument(textDocument, uri, token) {
|
||||
uri = uri ?? URI.parse(textDocument.uri);
|
||||
if (CancellationToken.is(token)) {
|
||||
return this.createAsync(uri, textDocument, token);
|
||||
}
|
||||
else {
|
||||
return this.create(uri, textDocument, token);
|
||||
}
|
||||
}
|
||||
fromString(text, uri, token) {
|
||||
if (CancellationToken.is(token)) {
|
||||
return this.createAsync(uri, text, token);
|
||||
}
|
||||
else {
|
||||
return this.create(uri, text, token);
|
||||
}
|
||||
}
|
||||
fromModel(model, uri) {
|
||||
return this.create(uri, { $model: model });
|
||||
}
|
||||
create(uri, content, options) {
|
||||
if (typeof content === 'string') {
|
||||
const parseResult = this.parse(uri, content, options);
|
||||
return this.createLangiumDocument(parseResult, uri, undefined, content);
|
||||
}
|
||||
else if ('$model' in content) {
|
||||
const parseResult = { value: content.$model, parserErrors: [], lexerErrors: [] };
|
||||
return this.createLangiumDocument(parseResult, uri);
|
||||
}
|
||||
else {
|
||||
const parseResult = this.parse(uri, content.getText(), options);
|
||||
return this.createLangiumDocument(parseResult, uri, content);
|
||||
}
|
||||
}
|
||||
async createAsync(uri, content, cancelToken) {
|
||||
if (typeof content === 'string') {
|
||||
const parseResult = await this.parseAsync(uri, content, cancelToken);
|
||||
return this.createLangiumDocument(parseResult, uri, undefined, content);
|
||||
}
|
||||
else {
|
||||
const parseResult = await this.parseAsync(uri, content.getText(), cancelToken);
|
||||
return this.createLangiumDocument(parseResult, uri, content);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a LangiumDocument from a given parse result.
|
||||
*
|
||||
* A TextDocument is created on demand if it is not provided as argument here. Usually this
|
||||
* should not be necessary because the main purpose of the TextDocument is to convert between
|
||||
* text ranges and offsets, which is done solely in LSP request handling.
|
||||
*
|
||||
* With the introduction of {@link update} below this method is supposed to be mainly called
|
||||
* during workspace initialization and on addition/recognition of new files, while changes in
|
||||
* existing documents are processed via {@link update}.
|
||||
*/
|
||||
createLangiumDocument(parseResult, uri, textDocument, text) {
|
||||
let document;
|
||||
if (textDocument) {
|
||||
document = {
|
||||
parseResult,
|
||||
uri,
|
||||
state: DocumentState.Parsed,
|
||||
references: [],
|
||||
textDocument
|
||||
};
|
||||
}
|
||||
else {
|
||||
const textDocumentGetter = this.createTextDocumentGetter(uri, text);
|
||||
document = {
|
||||
parseResult,
|
||||
uri,
|
||||
state: DocumentState.Parsed,
|
||||
references: [],
|
||||
get textDocument() {
|
||||
return textDocumentGetter();
|
||||
}
|
||||
};
|
||||
}
|
||||
parseResult.value.$document = document;
|
||||
return document;
|
||||
}
|
||||
async update(document, cancellationToken) {
|
||||
// The CST full text property contains the original text that was used to create the AST.
|
||||
const oldText = document.parseResult.value.$cstNode?.root.fullText;
|
||||
const textDocument = this.textDocuments?.get(document.uri.toString());
|
||||
const text = textDocument ? textDocument.getText() : await this.fileSystemProvider.readFile(document.uri);
|
||||
if (textDocument) {
|
||||
Object.defineProperty(document, 'textDocument', {
|
||||
value: textDocument
|
||||
});
|
||||
}
|
||||
else {
|
||||
const textDocumentGetter = this.createTextDocumentGetter(document.uri, text);
|
||||
Object.defineProperty(document, 'textDocument', {
|
||||
get: textDocumentGetter
|
||||
});
|
||||
}
|
||||
// Some of these documents can be pretty large, so parsing them again can be quite expensive.
|
||||
// Therefore, we only parse if the text has actually changed.
|
||||
if (oldText !== text) {
|
||||
document.parseResult = await this.parseAsync(document.uri, text, cancellationToken);
|
||||
document.parseResult.value.$document = document;
|
||||
}
|
||||
document.state = DocumentState.Parsed;
|
||||
return document;
|
||||
}
|
||||
parse(uri, text, options) {
|
||||
const services = this.serviceRegistry.getServices(uri);
|
||||
return services.parser.LangiumParser.parse(text, options);
|
||||
}
|
||||
parseAsync(uri, text, cancellationToken) {
|
||||
const services = this.serviceRegistry.getServices(uri);
|
||||
return services.parser.AsyncParser.parse(text, cancellationToken);
|
||||
}
|
||||
createTextDocumentGetter(uri, text) {
|
||||
const serviceRegistry = this.serviceRegistry;
|
||||
let textDoc = undefined;
|
||||
return () => {
|
||||
return textDoc ?? (textDoc = TextDocument.create(uri.toString(), serviceRegistry.getServices(uri).LanguageMetaData.languageId, 0, text ?? ''));
|
||||
};
|
||||
}
|
||||
}
|
||||
export class DefaultLangiumDocuments {
|
||||
constructor(services) {
|
||||
this.documentTrie = new UriTrie();
|
||||
this.services = services;
|
||||
this.langiumDocumentFactory = services.workspace.LangiumDocumentFactory;
|
||||
this.documentBuilder = () => services.workspace.DocumentBuilder;
|
||||
}
|
||||
get all() {
|
||||
return stream(this.documentTrie.all());
|
||||
}
|
||||
addDocument(document) {
|
||||
const uriString = document.uri.toString();
|
||||
if (this.documentTrie.has(uriString)) {
|
||||
throw new Error(`A document with the URI '${uriString}' is already present.`);
|
||||
}
|
||||
this.documentTrie.insert(uriString, document);
|
||||
}
|
||||
getDocument(uri) {
|
||||
const uriString = uri.toString();
|
||||
return this.documentTrie.find(uriString);
|
||||
}
|
||||
getDocuments(folder) {
|
||||
const uriString = folder.toString();
|
||||
return this.documentTrie.findAll(uriString);
|
||||
}
|
||||
async getOrCreateDocument(uri, cancellationToken) {
|
||||
let document = this.getDocument(uri);
|
||||
if (document) {
|
||||
return document;
|
||||
}
|
||||
document = await this.langiumDocumentFactory.fromUri(uri, cancellationToken);
|
||||
this.addDocument(document);
|
||||
return document;
|
||||
}
|
||||
createDocument(uri, text, cancellationToken) {
|
||||
if (cancellationToken) {
|
||||
return this.langiumDocumentFactory.fromString(text, uri, cancellationToken).then(document => {
|
||||
this.addDocument(document);
|
||||
return document;
|
||||
});
|
||||
}
|
||||
else {
|
||||
const document = this.langiumDocumentFactory.fromString(text, uri);
|
||||
this.addDocument(document);
|
||||
return document;
|
||||
}
|
||||
}
|
||||
hasDocument(uri) {
|
||||
return this.documentTrie.has(uri.toString());
|
||||
}
|
||||
/**
|
||||
* @deprecated Since 4.2 use `DocumentBuilder.resetToState(DocumentState.Changed)` instead
|
||||
* TODO remove this for the next major release
|
||||
*/
|
||||
invalidateDocument(uri) {
|
||||
const uriString = uri.toString();
|
||||
const langiumDoc = this.documentTrie.find(uriString);
|
||||
if (langiumDoc) {
|
||||
this.documentBuilder().resetToState(langiumDoc, DocumentState.Changed);
|
||||
}
|
||||
return langiumDoc;
|
||||
}
|
||||
deleteDocument(uri) {
|
||||
const uriString = uri.toString();
|
||||
const langiumDoc = this.documentTrie.find(uriString);
|
||||
if (langiumDoc) {
|
||||
langiumDoc.state = DocumentState.Changed;
|
||||
this.documentTrie.delete(uriString);
|
||||
}
|
||||
return langiumDoc;
|
||||
}
|
||||
deleteDocuments(folder) {
|
||||
const uriString = folder.toString();
|
||||
const langiumDocs = this.documentTrie.findAll(uriString);
|
||||
for (const langiumDoc of langiumDocs) {
|
||||
langiumDoc.state = DocumentState.Changed;
|
||||
}
|
||||
this.documentTrie.delete(uriString);
|
||||
return langiumDocs;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=documents.js.map
|
||||
1
frontend/node_modules/langium/lib/workspace/index.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/workspace/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/workspace/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC"}
|
||||
73
frontend/node_modules/langium/lib/workspace/profiler.d.ts
generated
vendored
Normal file
73
frontend/node_modules/langium/lib/workspace/profiler.d.ts
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2025 Y. Daveluy
|
||||
* 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 type { Stream } from '../utils/stream.js';
|
||||
export type ProfilingCategory = 'validating' | 'parsing' | 'linking';
|
||||
export interface LangiumProfiler {
|
||||
/**
|
||||
* Checks if the given category is active.
|
||||
* @param category The category to check.
|
||||
* @returns `true` if the category is active, `false` otherwise.
|
||||
*/
|
||||
isActive(category: ProfilingCategory): boolean;
|
||||
/**
|
||||
* Starts the profiling for the given categories. If none are provided, all categories are started.
|
||||
* @param categories The categories to start profiling for.
|
||||
*/
|
||||
start(...categories: ProfilingCategory[]): void;
|
||||
/**
|
||||
* Stops the profiling for the given categories. If none are provided, all categories are stopped.
|
||||
* @param categories The categories to stop profiling for.
|
||||
*/
|
||||
stop(...categories: ProfilingCategory[]): void;
|
||||
/**
|
||||
* Creates a new {@link ProfilingTask} for the given category.
|
||||
* @param category The category to create the task for.
|
||||
* @param taskId The identifier of the task.
|
||||
*/
|
||||
createTask(category: ProfilingCategory, taskId: string): ProfilingTask;
|
||||
/**
|
||||
* Gets the {@link ProfilingRecord}s for the given categories. If none are provided, all records are returned.
|
||||
* @param categories The categories to get the records for.
|
||||
* @returns A stream of profiling records.
|
||||
*/
|
||||
getRecords(...categories: ProfilingCategory[]): Stream<ProfilingRecord>;
|
||||
}
|
||||
export declare class DefaultLangiumProfiler implements LangiumProfiler {
|
||||
protected activeCategories: Set<ProfilingCategory>;
|
||||
protected readonly allCategories: ReadonlySet<ProfilingCategory>;
|
||||
protected readonly records: MultiMap<string, ProfilingRecord>;
|
||||
constructor(activeCategories?: Set<ProfilingCategory>);
|
||||
isActive(category: ProfilingCategory): boolean;
|
||||
start(...categories: ProfilingCategory[]): void;
|
||||
stop(...categories: ProfilingCategory[]): void;
|
||||
createTask(category: ProfilingCategory, taskId: string): ProfilingTask;
|
||||
protected dumpRecord(category: string, record: ProfilingRecord): ProfilingRecord;
|
||||
getRecords(...categories: ProfilingCategory[]): Stream<ProfilingRecord>;
|
||||
}
|
||||
export interface ProfilingRecord {
|
||||
identifier: string;
|
||||
date: Date;
|
||||
duration: number;
|
||||
entries: MultiMap<string, number>;
|
||||
}
|
||||
export declare class ProfilingTask {
|
||||
protected startTime?: number;
|
||||
protected readonly addRecord: (record: ProfilingRecord) => void;
|
||||
protected readonly identifier: string;
|
||||
protected readonly stack: Array<{
|
||||
id: string;
|
||||
start: number;
|
||||
content: number;
|
||||
}>;
|
||||
protected readonly entries: MultiMap<string, number>;
|
||||
constructor(addRecord: (record: ProfilingRecord) => void, identifier: string);
|
||||
start(): void;
|
||||
stop(): void;
|
||||
startSubTask(subTaskId: string): void;
|
||||
stopSubTask(subTaskId: string): void;
|
||||
}
|
||||
//# sourceMappingURL=profiler.d.ts.map
|
||||
118
frontend/node_modules/langium/lib/workspace/profiler.js
generated
vendored
Normal file
118
frontend/node_modules/langium/lib/workspace/profiler.js
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2025 Y. Daveluy
|
||||
* 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';
|
||||
export class DefaultLangiumProfiler {
|
||||
constructor(activeCategories) {
|
||||
this.activeCategories = new Set();
|
||||
this.allCategories = new Set(['validating', 'parsing', 'linking']);
|
||||
this.activeCategories = activeCategories ?? new Set(this.allCategories);
|
||||
this.records = new MultiMap();
|
||||
}
|
||||
isActive(category) {
|
||||
return this.activeCategories.has(category);
|
||||
}
|
||||
start(...categories) {
|
||||
if (!categories) {
|
||||
// Create a new set with all categories (immutable copy)
|
||||
this.activeCategories = new Set(this.allCategories);
|
||||
}
|
||||
else {
|
||||
categories.forEach(category => this.activeCategories.add(category));
|
||||
}
|
||||
}
|
||||
stop(...categories) {
|
||||
if (!categories) {
|
||||
this.activeCategories.clear();
|
||||
}
|
||||
else {
|
||||
categories.forEach(category => this.activeCategories.delete(category));
|
||||
}
|
||||
}
|
||||
createTask(category, taskId) {
|
||||
if (!this.isActive(category)) {
|
||||
throw new Error(`Category "${category}" is not active.`);
|
||||
}
|
||||
console.log(`Creating profiling task for '${category}.${taskId}'.`);
|
||||
return new ProfilingTask((record) => this.records.add(category, this.dumpRecord(category, record)), taskId);
|
||||
}
|
||||
dumpRecord(category, record) {
|
||||
console.info(`Task ${category}.${record.identifier} executed in ${record.duration.toFixed(2)}ms and ended at ${record.date.toISOString()}`);
|
||||
const result = [];
|
||||
for (const key of record.entries.keys()) {
|
||||
const values = record.entries.get(key);
|
||||
const duration = values.reduce((p, c) => p + c);
|
||||
result.push({ name: `${record.identifier}.${key}`, count: values.length, duration: duration });
|
||||
}
|
||||
// sum all duration
|
||||
const taskInternalDuration = record.duration - result.map(r => r.duration).reduce((a, b) => a + b, 0);
|
||||
result.push({ name: record.identifier, count: 1, duration: taskInternalDuration });
|
||||
result.sort((a, b) => b.duration - a.duration);
|
||||
function Round(value) { return Math.round(100 * value) / 100; }
|
||||
console.table(result.map(e => { return { Element: e.name, Count: e.count, 'Self %': Round(100 * e.duration / record.duration), 'Time (ms)': Round(e.duration) }; }));
|
||||
return record;
|
||||
}
|
||||
getRecords(...categories) {
|
||||
if (categories.length === 0) {
|
||||
// return all records
|
||||
return this.records.values();
|
||||
}
|
||||
else {
|
||||
// return records for the given categories
|
||||
return this.records.entries().filter((e) => categories.some(c => c === e[0])).flatMap(e => e[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class ProfilingTask {
|
||||
constructor(addRecord, identifier) {
|
||||
this.stack = [];
|
||||
this.entries = new MultiMap();
|
||||
this.addRecord = addRecord;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
start() {
|
||||
if (this.startTime !== undefined) {
|
||||
throw new Error(`Task "${this.identifier}" is already started.`);
|
||||
}
|
||||
this.startTime = performance.now();
|
||||
}
|
||||
stop() {
|
||||
if (this.startTime === undefined) {
|
||||
throw new Error(`Task "${this.identifier}" was not started.`);
|
||||
}
|
||||
if (this.stack.length !== 0) {
|
||||
throw new Error(`Task "${this.identifier}" cannot be stopped before sub-task(s): ${this.stack.map(s => s.id).join(', ')}.`);
|
||||
}
|
||||
const record = {
|
||||
identifier: this.identifier,
|
||||
date: new Date(),
|
||||
duration: performance.now() - this.startTime,
|
||||
entries: this.entries
|
||||
};
|
||||
this.addRecord(record);
|
||||
this.startTime = undefined;
|
||||
this.entries.clear();
|
||||
}
|
||||
startSubTask(subTaskId) {
|
||||
this.stack.push({ id: subTaskId, start: performance.now(), content: 0 });
|
||||
}
|
||||
stopSubTask(subTaskId) {
|
||||
const subStack = this.stack.pop();
|
||||
if (!subStack) {
|
||||
throw new Error(`Task "${this.identifier}.${subTaskId}" was not started.`);
|
||||
}
|
||||
if (subStack.id !== subTaskId) {
|
||||
throw new Error(`Sub-Task "${subStack.id}" is not already stopped.`);
|
||||
}
|
||||
const duration = performance.now() - subStack.start;
|
||||
if (this.stack.at(-1) !== undefined) {
|
||||
this.stack[this.stack.length - 1].content += duration;
|
||||
}
|
||||
// we are interested here by the duration of the current sub-task without the duration of nested sub-tasks.
|
||||
const selfDuration = duration - subStack.content;
|
||||
this.entries.add(subTaskId, selfDuration);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=profiler.js.map
|
||||
1
frontend/node_modules/langium/lib/workspace/workspace-lock.d.ts.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/workspace/workspace-lock.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"workspace-lock.d.ts","sourceRoot":"","sources":["../../src/workspace/workspace-lock.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAwC,iBAAiB,EAA2B,MAAM,0BAA0B,CAAC;AAC5H,OAAO,EAA4D,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAExH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/E;;;;;;;;OAQG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnD;;OAEG;IACH,WAAW,IAAI,IAAI,CAAC;CACvB;AAUD,qBAAa,oBAAqB,YAAW,aAAa;IAEtD,OAAO,CAAC,mBAAmB,CAAkE;IAC7F,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,IAAI,CAAQ;IAEpB,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9E,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,OAAO,CAAC,OAAO;YAYD,oBAAoB;IAiClC,WAAW,IAAI,IAAI;CAGtB"}
|
||||
75
frontend/node_modules/langium/lib/workspace/workspace-lock.js
generated
vendored
Normal file
75
frontend/node_modules/langium/lib/workspace/workspace-lock.js
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/******************************************************************************
|
||||
* 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 { CancellationToken, CancellationTokenSource } from '../utils/cancellation.js';
|
||||
import { Deferred, isOperationCancelled, startCancelableOperation } from '../utils/promise-utils.js';
|
||||
export class DefaultWorkspaceLock {
|
||||
constructor() {
|
||||
this.previousTokenSource = new CancellationTokenSource();
|
||||
this.writeQueue = [];
|
||||
this.readQueue = [];
|
||||
this.done = true;
|
||||
}
|
||||
write(action) {
|
||||
this.cancelWrite();
|
||||
const tokenSource = startCancelableOperation();
|
||||
this.previousTokenSource = tokenSource;
|
||||
return this.enqueue(this.writeQueue, action, tokenSource.token);
|
||||
}
|
||||
read(action) {
|
||||
return this.enqueue(this.readQueue, action);
|
||||
}
|
||||
enqueue(queue, action, cancellationToken = CancellationToken.None) {
|
||||
const deferred = new Deferred();
|
||||
const entry = {
|
||||
action,
|
||||
deferred,
|
||||
cancellationToken
|
||||
};
|
||||
queue.push(entry);
|
||||
this.performNextOperation();
|
||||
return deferred.promise;
|
||||
}
|
||||
async performNextOperation() {
|
||||
if (!this.done) {
|
||||
return;
|
||||
}
|
||||
const entries = [];
|
||||
if (this.writeQueue.length > 0) {
|
||||
// Just perform the next write action
|
||||
entries.push(this.writeQueue.shift());
|
||||
}
|
||||
else if (this.readQueue.length > 0) {
|
||||
// Empty the read queue and perform all actions in parallel
|
||||
entries.push(...this.readQueue.splice(0, this.readQueue.length));
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
this.done = false;
|
||||
await Promise.all(entries.map(async ({ action, deferred, cancellationToken }) => {
|
||||
try {
|
||||
// Move the execution of the action to the next event loop tick via `Promise.resolve()`
|
||||
const result = await Promise.resolve().then(() => action(cancellationToken));
|
||||
deferred.resolve(result);
|
||||
}
|
||||
catch (err) {
|
||||
if (isOperationCancelled(err)) {
|
||||
// If the operation was cancelled, we don't want to reject the promise
|
||||
deferred.resolve(undefined);
|
||||
}
|
||||
else {
|
||||
deferred.reject(err);
|
||||
}
|
||||
}
|
||||
}));
|
||||
this.done = true;
|
||||
this.performNextOperation();
|
||||
}
|
||||
cancelWrite() {
|
||||
this.previousTokenSource.cancel();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=workspace-lock.js.map
|
||||
1
frontend/node_modules/langium/lib/workspace/workspace-lock.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/workspace/workspace-lock.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"workspace-lock.js","sourceRoot":"","sources":["../../src/workspace/workspace-lock.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAwC,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC5H,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,wBAAwB,EAAqB,MAAM,2BAA2B,CAAC;AAwCxH,MAAM,OAAO,oBAAoB;IAAjC;QAEY,wBAAmB,GAAoC,IAAI,uBAAuB,EAAE,CAAC;QACrF,eAAU,GAAgB,EAAE,CAAC;QAC7B,cAAS,GAAgB,EAAE,CAAC;QAC5B,SAAI,GAAG,IAAI,CAAC;IA6DxB,CAAC;IA3DG,KAAK,CAAC,MAAwD;QAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,WAAW,GAAG,wBAAwB,EAAE,CAAC;QAC/C,IAAI,CAAC,mBAAmB,GAAG,WAAW,CAAC;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,CAAI,MAA6B;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAEO,OAAO,CAAW,KAAkB,EAAE,MAAqB,EAAE,iBAAiB,GAAG,iBAAiB,CAAC,IAAI;QAC3G,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAW,CAAC;QACzC,MAAM,KAAK,GAAc;YACrB,MAAM;YACN,QAAQ;YACR,iBAAiB;SACpB,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,OAAO,QAAQ,CAAC,OAAqB,CAAC;IAC1C,CAAC;IAEO,KAAK,CAAC,oBAAoB;QAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACb,OAAO;QACX,CAAC;QACD,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,qCAAqC;YACrC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAG,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,2DAA2D;YAC3D,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACJ,OAAO;QACX,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,EAAE;YAC5E,IAAI,CAAC;gBACD,uFAAuF;gBACvF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;gBAC7E,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,IAAI,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5B,sEAAsE;oBACtE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACJ,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,CAAC;YACL,CAAC;QACL,CAAC,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAChC,CAAC;IAED,WAAW;QACP,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC;IACtC,CAAC;CACJ"}
|
||||
1
frontend/node_modules/langium/lib/workspace/workspace-manager.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/workspace/workspace-manager.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"workspace-manager.js","sourceRoot":"","sources":["../../src/workspace/workspace-manager.ts"],"names":[],"mappings":"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"}
|
||||
Reference in New Issue
Block a user