完成世界书、骰子、apiconfig页面处理
This commit is contained in:
279
frontend/node_modules/langium/lib/utils/ast-utils.js
generated
vendored
Normal file
279
frontend/node_modules/langium/lib/utils/ast-utils.js
generated
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
/******************************************************************************
|
||||
* 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 { isAstNode, isMultiReference, isReference } from '../syntax-tree.js';
|
||||
import { DONE_RESULT, StreamImpl, TreeStreamImpl } from './stream.js';
|
||||
import { inRange } from './cst-utils.js';
|
||||
/**
|
||||
* Link the `$container` and other related properties of every AST node that is directly contained
|
||||
* in the given `node`.
|
||||
*/
|
||||
export function linkContentToContainer(node, options = {}) {
|
||||
for (const [name, value] of Object.entries(node)) {
|
||||
if (!name.startsWith('$')) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item, index) => {
|
||||
if (isAstNode(item)) {
|
||||
item.$container = node;
|
||||
item.$containerProperty = name;
|
||||
item.$containerIndex = index;
|
||||
if (options.deep) {
|
||||
linkContentToContainer(item, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (isAstNode(value)) {
|
||||
value.$container = node;
|
||||
value.$containerProperty = name;
|
||||
if (options.deep) {
|
||||
linkContentToContainer(value, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Walk along the hierarchy of containers from the given AST node to the root and return the first
|
||||
* node that matches the type predicate. If the start node itself matches, it is returned.
|
||||
* If no container matches, `undefined` is returned.
|
||||
*/
|
||||
export function getContainerOfType(node, typePredicate) {
|
||||
let item = node;
|
||||
while (item) {
|
||||
if (typePredicate(item)) {
|
||||
return item;
|
||||
}
|
||||
item = item.$container;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Walk along the hierarchy of containers from the given AST node to the root and check for existence
|
||||
* of a container that matches the given predicate. The start node is included in the checks.
|
||||
*/
|
||||
export function hasContainerOfType(node, predicate) {
|
||||
let item = node;
|
||||
while (item) {
|
||||
if (predicate(item)) {
|
||||
return true;
|
||||
}
|
||||
item = item.$container;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Retrieve the document in which the given AST node is contained. A reference to the document is
|
||||
* usually held by the root node of the AST.
|
||||
*
|
||||
* @throws an error if the node is not contained in a document.
|
||||
*/
|
||||
export function getDocument(node) {
|
||||
const rootNode = findRootNode(node);
|
||||
const result = rootNode.$document;
|
||||
if (!result) {
|
||||
throw new Error('AST node has no document.');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Returns the root node of the given AST node by following the `$container` references.
|
||||
*/
|
||||
export function findRootNode(node) {
|
||||
while (node.$container) {
|
||||
node = node.$container;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
/**
|
||||
* Returns all AST nodes that are referenced by the given reference or multi-reference.
|
||||
*/
|
||||
export function getReferenceNodes(reference) {
|
||||
if (isReference(reference)) {
|
||||
return reference.ref ? [reference.ref] : [];
|
||||
}
|
||||
else if (isMultiReference(reference)) {
|
||||
return reference.items.map(item => item.ref);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* Create a stream of all AST nodes that are directly contained in the given node. This includes
|
||||
* single-valued as well as multi-valued (array) properties.
|
||||
*/
|
||||
export function streamContents(node, options) {
|
||||
if (!node) {
|
||||
throw new Error('Node must be an AstNode.');
|
||||
}
|
||||
const range = options?.range;
|
||||
return new StreamImpl(() => ({
|
||||
keys: Object.keys(node),
|
||||
keyIndex: 0,
|
||||
arrayIndex: 0
|
||||
}), state => {
|
||||
while (state.keyIndex < state.keys.length) {
|
||||
const property = state.keys[state.keyIndex];
|
||||
if (!property.startsWith('$')) {
|
||||
const value = node[property];
|
||||
if (isAstNode(value)) {
|
||||
state.keyIndex++;
|
||||
if (isAstNodeInRange(value, range)) {
|
||||
return { done: false, value };
|
||||
}
|
||||
}
|
||||
else if (Array.isArray(value)) {
|
||||
while (state.arrayIndex < value.length) {
|
||||
const index = state.arrayIndex++;
|
||||
const element = value[index];
|
||||
if (isAstNode(element) && isAstNodeInRange(element, range)) {
|
||||
return { done: false, value: element };
|
||||
}
|
||||
}
|
||||
state.arrayIndex = 0;
|
||||
}
|
||||
}
|
||||
state.keyIndex++;
|
||||
}
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Create a stream of all AST nodes that are directly and indirectly contained in the given root node.
|
||||
* This does not include the root node itself.
|
||||
*/
|
||||
export function streamAllContents(root, options) {
|
||||
if (!root) {
|
||||
throw new Error('Root node must be an AstNode.');
|
||||
}
|
||||
return new TreeStreamImpl(root, node => streamContents(node, options));
|
||||
}
|
||||
/**
|
||||
* Create a stream of all AST nodes that are directly and indirectly contained in the given root node,
|
||||
* including the root node itself.
|
||||
*/
|
||||
export function streamAst(root, options) {
|
||||
if (!root) {
|
||||
throw new Error('Root node must be an AstNode.');
|
||||
}
|
||||
else if (options?.range && !isAstNodeInRange(root, options.range)) {
|
||||
// Return an empty stream if the root node isn't in range
|
||||
return new TreeStreamImpl(root, () => []);
|
||||
}
|
||||
return new TreeStreamImpl(root, node => streamContents(node, options), { includeRoot: true });
|
||||
}
|
||||
function isAstNodeInRange(astNode, range) {
|
||||
if (!range) {
|
||||
return true;
|
||||
}
|
||||
const nodeRange = astNode.$cstNode?.range;
|
||||
if (!nodeRange) {
|
||||
return false;
|
||||
}
|
||||
return inRange(nodeRange, range);
|
||||
}
|
||||
/**
|
||||
* Create a stream of all cross-references that are held by the given AST node. This includes
|
||||
* single-valued as well as multi-valued (array) properties.
|
||||
*/
|
||||
export function streamReferences(node) {
|
||||
return new StreamImpl(() => ({
|
||||
keys: Object.keys(node),
|
||||
keyIndex: 0,
|
||||
arrayIndex: 0
|
||||
}), state => {
|
||||
while (state.keyIndex < state.keys.length) {
|
||||
const property = state.keys[state.keyIndex];
|
||||
if (!property.startsWith('$')) {
|
||||
const value = node[property];
|
||||
if (isReference(value) || isMultiReference(value)) {
|
||||
state.keyIndex++;
|
||||
return { done: false, value: { reference: value, container: node, property } };
|
||||
}
|
||||
else if (Array.isArray(value)) {
|
||||
while (state.arrayIndex < value.length) {
|
||||
const index = state.arrayIndex++;
|
||||
const element = value[index];
|
||||
if (isReference(element) || isMultiReference(value)) {
|
||||
return { done: false, value: { reference: element, container: node, property, index } };
|
||||
}
|
||||
}
|
||||
state.arrayIndex = 0;
|
||||
}
|
||||
}
|
||||
state.keyIndex++;
|
||||
}
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Assigns all mandatory AST properties to the specified node.
|
||||
*
|
||||
* @param reflection Reflection object used to gather mandatory properties for the node.
|
||||
* @param node Specified node is modified in place and properties are directly assigned.
|
||||
*/
|
||||
export function assignMandatoryProperties(reflection, node) {
|
||||
const typeMetaData = reflection.getTypeMetaData(node.$type);
|
||||
const genericNode = node;
|
||||
for (const property of Object.values(typeMetaData.properties)) {
|
||||
// Only set the value if the property is not already set and if it has a default value
|
||||
if (property.defaultValue !== undefined && genericNode[property.name] === undefined) {
|
||||
genericNode[property.name] = copyDefaultValue(property.defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
function copyDefaultValue(propertyType) {
|
||||
if (Array.isArray(propertyType)) {
|
||||
return [...propertyType.map(copyDefaultValue)];
|
||||
}
|
||||
else {
|
||||
return propertyType;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a deep copy of the specified AST node.
|
||||
* The resulting copy will only contain semantically relevant information, such as the `$type` property and AST properties.
|
||||
*
|
||||
* @param node The AST node to deeply copy.
|
||||
* @param buildReference References are not copied, instead this function is called to rebuild them.
|
||||
* @param trace For the sake of tracking copied nodes and their originals a `trace` map can be provided (optional).
|
||||
*/
|
||||
export function copyAstNode(node, buildReference, trace) {
|
||||
const copy = { $type: node.$type };
|
||||
if (trace) {
|
||||
trace.set(node, copy);
|
||||
trace.set(copy, node);
|
||||
}
|
||||
for (const [name, value] of Object.entries(node)) {
|
||||
if (!name.startsWith('$')) {
|
||||
if (isAstNode(value)) {
|
||||
copy[name] = copyAstNode(value, buildReference, trace);
|
||||
}
|
||||
else if (isReference(value)) {
|
||||
copy[name] = buildReference(copy, name, value.$refNode, value.$refText, value);
|
||||
}
|
||||
else if (Array.isArray(value)) {
|
||||
const copiedArray = [];
|
||||
for (const element of value) {
|
||||
if (isAstNode(element)) {
|
||||
copiedArray.push(copyAstNode(element, buildReference, trace));
|
||||
}
|
||||
else if (isReference(element)) {
|
||||
copiedArray.push(buildReference(copy, name, element.$refNode, element.$refText, element));
|
||||
}
|
||||
else {
|
||||
copiedArray.push(element);
|
||||
}
|
||||
}
|
||||
copy[name] = copiedArray;
|
||||
}
|
||||
else {
|
||||
copy[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
linkContentToContainer(copy, { deep: true });
|
||||
return copy;
|
||||
}
|
||||
//# sourceMappingURL=ast-utils.js.map
|
||||
74
frontend/node_modules/langium/lib/utils/caching.d.ts
generated
vendored
Normal file
74
frontend/node_modules/langium/lib/utils/caching.d.ts
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/******************************************************************************
|
||||
* 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 { Disposable } from './disposable.js';
|
||||
import type { URI } from './uri-utils.js';
|
||||
import type { LangiumSharedCoreServices } from '../services.js';
|
||||
import type { DocumentState } from '../workspace/documents.js';
|
||||
export declare abstract class DisposableCache implements Disposable {
|
||||
protected toDispose: Disposable[];
|
||||
protected isDisposed: boolean;
|
||||
onDispose(disposable: Disposable): void;
|
||||
dispose(): void;
|
||||
protected throwIfDisposed(): void;
|
||||
abstract clear(): void;
|
||||
}
|
||||
export declare class SimpleCache<K, V> extends DisposableCache {
|
||||
protected readonly cache: Map<K, V>;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value: V): void;
|
||||
get(key: K): V | undefined;
|
||||
get(key: K, provider: () => V): V;
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
}
|
||||
export declare class ContextCache<Context, Key, Value, ContextKey = Context> extends DisposableCache {
|
||||
private readonly cache;
|
||||
private readonly converter;
|
||||
constructor(converter?: (input: Context) => ContextKey);
|
||||
has(contextKey: Context, key: Key): boolean;
|
||||
set(contextKey: Context, key: Key, value: Value): void;
|
||||
get(contextKey: Context, key: Key): Value | undefined;
|
||||
get(contextKey: Context, key: Key, provider: () => Value): Value;
|
||||
delete(contextKey: Context, key: Key): boolean;
|
||||
clear(): void;
|
||||
clear(contextKey: Context): void;
|
||||
protected cacheForContext(contextKey: Context): Map<Key, Value>;
|
||||
}
|
||||
/**
|
||||
* Every key/value pair in this cache is scoped to a document.
|
||||
* If this document is changed or deleted, all associated key/value pairs are deleted.
|
||||
*/
|
||||
export declare class DocumentCache<K, V> extends ContextCache<URI | string, K, V, string> {
|
||||
/**
|
||||
* Creates a new document cache.
|
||||
*
|
||||
* @param sharedServices Service container instance to hook into document lifecycle events.
|
||||
* @param state Optional document state on which the cache should evict.
|
||||
* If not provided, the cache will evict on `DocumentBuilder#onUpdate`.
|
||||
* *Deleted* documents are considered in both cases.
|
||||
*
|
||||
* Providing a state here will use `DocumentBuilder#onDocumentPhase` instead,
|
||||
* which triggers on all documents that have been affected by this change, assuming that the
|
||||
* state is `DocumentState.Linked` or a later state.
|
||||
*/
|
||||
constructor(sharedServices: LangiumSharedCoreServices, state?: DocumentState);
|
||||
}
|
||||
/**
|
||||
* Every key/value pair in this cache is scoped to the whole workspace.
|
||||
* If any document in the workspace is added, changed or deleted, the whole cache is evicted.
|
||||
*/
|
||||
export declare class WorkspaceCache<K, V> extends SimpleCache<K, V> {
|
||||
/**
|
||||
* Creates a new workspace cache.
|
||||
*
|
||||
* @param sharedServices Service container instance to hook into document lifecycle events.
|
||||
* @param state Optional document state on which the cache should evict.
|
||||
* If not provided, the cache will evict on `DocumentBuilder#onUpdate`.
|
||||
* *Deleted* documents are considered in both cases.
|
||||
*/
|
||||
constructor(sharedServices: LangiumSharedCoreServices, state?: DocumentState);
|
||||
}
|
||||
//# sourceMappingURL=caching.d.ts.map
|
||||
1
frontend/node_modules/langium/lib/utils/caching.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/caching.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"caching.js","sourceRoot":"","sources":["../../src/utils/caching.ts"],"names":[],"mappings":"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"}
|
||||
8
frontend/node_modules/langium/lib/utils/cancellation.js
generated
vendored
Normal file
8
frontend/node_modules/langium/lib/utils/cancellation.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2024 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.
|
||||
******************************************************************************/
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
export * from 'vscode-jsonrpc/lib/common/cancellation.js';
|
||||
//# sourceMappingURL=cancellation.js.map
|
||||
1
frontend/node_modules/langium/lib/utils/cancellation.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/cancellation.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cancellation.js","sourceRoot":"","sources":["../../src/utils/cancellation.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,iDAAiD;AACjD,cAAc,2CAA2C,CAAC"}
|
||||
1
frontend/node_modules/langium/lib/utils/disposable.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/disposable.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"disposable.js","sourceRoot":"","sources":["../../src/utils/disposable.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAgBhF,MAAM,KAAW,UAAU,CAQ1B;AARD,WAAiB,UAAU;IAGvB,SAAgB,MAAM,CAAC,QAAoC;QACvD,OAAO;YACH,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,QAAQ,EAAE;SACxC,CAAC;IACN,CAAC;IAJe,iBAAM,SAIrB,CAAA;AACL,CAAC,EARgB,UAAU,KAAV,UAAU,QAQ1B"}
|
||||
7
frontend/node_modules/langium/lib/utils/event.d.ts
generated
vendored
Normal file
7
frontend/node_modules/langium/lib/utils/event.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2024 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 'vscode-jsonrpc/lib/common/events.js';
|
||||
//# sourceMappingURL=event.d.ts.map
|
||||
1
frontend/node_modules/langium/lib/utils/event.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/event.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/utils/event.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,iDAAiD;AACjD,cAAc,qCAAqC,CAAC"}
|
||||
1
frontend/node_modules/langium/lib/utils/grammar-loader.js.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/grammar-loader.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-loader.js","sourceRoot":"","sources":["../../src/utils/grammar-loader.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAE9F,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,KAAK,GAAG,MAAM,+BAA+B,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,MAAM,oBAAoB,GAA4D;IAClF,OAAO,EAAE,GAAG,EAAE,CAAC,SAAmC;IAClD,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;QACrB,eAAe,EAAE,KAAK;QACtB,cAAc,EAAE,CAAC,UAAU,CAAC;QAC5B,UAAU,EAAE,SAAS;KACxB,CAAC;CACL,CAAC;AAEF,MAAM,0BAA0B,GAAwE;IACpG,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,2BAA2B,EAAE;CAC7D,CAAC;AAEF,SAAS,4BAA4B;IACjC,MAAM,MAAM,GAAG,MAAM,CACjB,6BAA6B,CAAC,eAAe,CAAC,EAC9C,0BAA0B,CAC7B,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAClB,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC,EACnC,oBAAoB,CACvB,CAAC;IACF,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAyB,CAAC;IAC7F,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,OAAO,CAAC,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC,CAAC;IAC/H,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
||||
127
frontend/node_modules/langium/lib/utils/grammar-utils.d.ts
generated
vendored
Normal file
127
frontend/node_modules/langium/lib/utils/grammar-utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/******************************************************************************
|
||||
* 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 * as ast from '../languages/generated/ast.js';
|
||||
import type { AstNode, CstNode } from '../syntax-tree.js';
|
||||
/**
|
||||
* Returns the entry rule of the given grammar, if any. If the grammar file does not contain an entry rule,
|
||||
* the result is `undefined`.
|
||||
*/
|
||||
export declare function getEntryRule(grammar: ast.Grammar): ast.ParserRule | undefined;
|
||||
/**
|
||||
* Returns all hidden terminal rules of the given grammar, if any.
|
||||
*/
|
||||
export declare function getHiddenRules(grammar: ast.Grammar): ast.AbstractRule[];
|
||||
/**
|
||||
* Returns all rules that can be reached from the topmost rules of the specified grammar (entry and hidden terminal rules).
|
||||
*
|
||||
* @param grammar The grammar that contains all rules
|
||||
* @param allTerminals Whether or not to include terminals that are referenced only by other terminals
|
||||
* @returns A list of referenced parser and terminal rules. If the grammar contains no entry rule,
|
||||
* this function returns all rules of the specified grammar.
|
||||
*/
|
||||
export declare function getAllReachableRules(grammar: ast.Grammar, allTerminals: boolean): Set<ast.AbstractRule>;
|
||||
/**
|
||||
* Returns all parser rules which provide types which are used in the grammar as type in cross-references.
|
||||
* @param grammar the grammar to investigate
|
||||
* @returns the set of parser rules whose contributed types are used as type in cross-references
|
||||
*/
|
||||
export declare function getAllRulesUsedForCrossReferences(grammar: ast.Grammar): Set<ast.ParserRule>;
|
||||
/**
|
||||
* Determines the grammar expression used to parse a cross-reference (usually a reference to a terminal rule).
|
||||
* A cross-reference can declare this expression explicitly in the form `[Type : Terminal]`, but if `Terminal`
|
||||
* is omitted, this function attempts to infer it from the name of the referenced `Type` (using `findNameAssignment`).
|
||||
*
|
||||
* Returns the grammar expression used to parse the given cross-reference, or `undefined` if it is not declared
|
||||
* and cannot be inferred.
|
||||
*/
|
||||
export declare function getCrossReferenceTerminal(crossRef: ast.CrossReference): ast.AbstractElement | undefined;
|
||||
/**
|
||||
* Determines whether the given terminal rule represents a comment. This is true if the rule is marked
|
||||
* as `hidden` and it does not match white space. This means every hidden token (i.e. excluded from the AST)
|
||||
* that contains visible characters is considered a comment.
|
||||
*/
|
||||
export declare function isCommentTerminal(terminalRule: ast.TerminalRule): boolean;
|
||||
/**
|
||||
* Find all CST nodes within the given node that contribute to the specified property.
|
||||
*
|
||||
* @param node A CST node in which to look for property assignments. If this is undefined, the result is an empty array.
|
||||
* @param property A property name of the constructed AST node. If this is undefined, the result is an empty array.
|
||||
*/
|
||||
export declare function findNodesForProperty(node: CstNode | undefined, property: string | undefined): CstNode[];
|
||||
/**
|
||||
* Find a single CST node within the given node that contributes to the specified property.
|
||||
*
|
||||
* @param node A CST node in which to look for property assignments. If this is undefined, the result is `undefined`.
|
||||
* @param property A property name of the constructed AST node. If this is undefined, the result is `undefined`.
|
||||
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
|
||||
* specified index exceeds the number of assignments to the property, the last found node is returned. Otherwise,
|
||||
* the node with the specified index is returned.
|
||||
*/
|
||||
export declare function findNodeForProperty(node: CstNode | undefined, property: string | undefined, index?: number): CstNode | undefined;
|
||||
/**
|
||||
* Find all CST nodes within the given node that correspond to the specified keyword.
|
||||
*
|
||||
* @param node A CST node in which to look for keywords. If this is undefined, the result is an empty array.
|
||||
* @param keyword A keyword as specified in the grammar.
|
||||
*/
|
||||
export declare function findNodesForKeyword(node: CstNode | undefined, keyword: string): CstNode[];
|
||||
/**
|
||||
* Find a single CST node within the given node that corresponds to the specified keyword.
|
||||
*
|
||||
* @param node A CST node in which to look for keywords. If this is undefined, the result is `undefined`.
|
||||
* @param keyword A keyword as specified in the grammar.
|
||||
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
|
||||
* specified index exceeds the number of keyword occurrences, the last found node is returned. Otherwise,
|
||||
* the node with the specified index is returned.
|
||||
*/
|
||||
export declare function findNodeForKeyword(node: CstNode | undefined, keyword: string, index?: number): CstNode | undefined;
|
||||
export declare function findNodesForKeywordInternal(node: CstNode, keyword: string, element: AstNode | undefined): CstNode[];
|
||||
/**
|
||||
* If the given CST node was parsed in the context of a property assignment, the respective `Assignment` grammar
|
||||
* node is returned. If no assignment is found, the result is `undefined`.
|
||||
*
|
||||
* @param cstNode A CST node for which to find a property assignment.
|
||||
*/
|
||||
export declare function findAssignment(cstNode: CstNode): ast.Assignment | undefined;
|
||||
/**
|
||||
* Find an assignment to the `name` property for the given grammar type. This requires the `type` to be inferred
|
||||
* from a parser rule, and that rule must contain an assignment to the `name` property. In all other cases,
|
||||
* this function returns `undefined`.
|
||||
*/
|
||||
export declare function findNameAssignment(type: ast.AbstractType): ast.Assignment | undefined;
|
||||
export declare function getActionAtElement(element: ast.AbstractElement): ast.Action | undefined;
|
||||
export type Cardinality = '?' | '*' | '+' | undefined;
|
||||
export type Operator = '=' | '+=' | '?=' | undefined;
|
||||
export declare function isOptionalCardinality(cardinality?: Cardinality, element?: ast.AbstractElement): boolean;
|
||||
export declare function isArrayCardinality(cardinality?: Cardinality): boolean;
|
||||
export declare function isArrayOperator(operator?: Operator): boolean;
|
||||
/**
|
||||
* Determines whether the given parser rule is a _data type rule_, meaning that it has a
|
||||
* primitive return type like `number`, `boolean`, etc.
|
||||
*/
|
||||
export declare function isDataTypeRule(rule: ast.ParserRule): boolean;
|
||||
export declare function isDataType(type: ast.Type): boolean;
|
||||
export declare function getExplicitRuleType(rule: ast.AbstractRule): string | undefined;
|
||||
export declare function getTypeName(type: ast.AbstractType | ast.Action): string;
|
||||
export declare function getActionType(action: ast.Action): string | undefined;
|
||||
/**
|
||||
* This function is used at development time (for code generation and the internal type system) to get the type of the AST node produced by the given rule.
|
||||
* For data type rules, the name of the rule is returned,
|
||||
* e.g. "INT_value returns number: MY_INT;" returns "INT_value".
|
||||
* @param rule the given rule
|
||||
* @returns the name of the AST node type of the rule
|
||||
*/
|
||||
export declare function getRuleTypeName(rule: ast.AbstractRule): string;
|
||||
/**
|
||||
* This function is used at runtime to get the actual type of the values produced by the given rule at runtime.
|
||||
* For data type rules, the name of the declared return type of the rule is returned (if any),
|
||||
* e.g. "INT_value returns number: MY_INT;" returns "number".
|
||||
* @param rule the given rule
|
||||
* @returns the name of the type of the produced values of the rule at runtime
|
||||
*/
|
||||
export declare function getRuleType(rule: ast.AbstractRule): string;
|
||||
export declare function terminalRegex(terminalRule: ast.TerminalRule): RegExp;
|
||||
//# sourceMappingURL=grammar-utils.d.ts.map
|
||||
606
frontend/node_modules/langium/lib/utils/grammar-utils.js
generated
vendored
Normal file
606
frontend/node_modules/langium/lib/utils/grammar-utils.js
generated
vendored
Normal file
@@ -0,0 +1,606 @@
|
||||
/******************************************************************************
|
||||
* 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 { assertUnreachable } from '../utils/errors.js';
|
||||
import * as ast from '../languages/generated/ast.js';
|
||||
import { isCompositeCstNode } from '../syntax-tree.js';
|
||||
import { getContainerOfType, streamAllContents } from './ast-utils.js';
|
||||
import { streamCst } from './cst-utils.js';
|
||||
import { escapeRegExp, isWhitespace } from './regexp-utils.js';
|
||||
/**
|
||||
* Returns the entry rule of the given grammar, if any. If the grammar file does not contain an entry rule,
|
||||
* the result is `undefined`.
|
||||
*/
|
||||
export function getEntryRule(grammar) {
|
||||
return grammar.rules.find(e => ast.isParserRule(e) && e.entry);
|
||||
}
|
||||
/**
|
||||
* Returns all hidden terminal rules of the given grammar, if any.
|
||||
*/
|
||||
export function getHiddenRules(grammar) {
|
||||
return grammar.rules.filter(e => ast.isTerminalRule(e) && e.hidden);
|
||||
}
|
||||
/**
|
||||
* Returns all rules that can be reached from the topmost rules of the specified grammar (entry and hidden terminal rules).
|
||||
*
|
||||
* @param grammar The grammar that contains all rules
|
||||
* @param allTerminals Whether or not to include terminals that are referenced only by other terminals
|
||||
* @returns A list of referenced parser and terminal rules. If the grammar contains no entry rule,
|
||||
* this function returns all rules of the specified grammar.
|
||||
*/
|
||||
export function getAllReachableRules(grammar, allTerminals) {
|
||||
const ruleNames = new Set();
|
||||
const entryRule = getEntryRule(grammar);
|
||||
if (!entryRule) {
|
||||
return new Set(grammar.rules);
|
||||
}
|
||||
const topMostRules = [entryRule].concat(getHiddenRules(grammar));
|
||||
for (const rule of topMostRules) {
|
||||
ruleDfs(rule, ruleNames, allTerminals);
|
||||
}
|
||||
const rules = new Set();
|
||||
for (const rule of grammar.rules) {
|
||||
if (ruleNames.has(rule.name) || (ast.isTerminalRule(rule) && rule.hidden)) {
|
||||
rules.add(rule);
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
function ruleDfs(rule, visitedSet, allTerminals) {
|
||||
visitedSet.add(rule.name);
|
||||
streamAllContents(rule).forEach(node => {
|
||||
if (ast.isRuleCall(node) || (allTerminals && ast.isTerminalRuleCall(node))) {
|
||||
const refRule = node.rule.ref;
|
||||
if (refRule && !visitedSet.has(refRule.name)) {
|
||||
ruleDfs(refRule, visitedSet, allTerminals);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Returns all parser rules which provide types which are used in the grammar as type in cross-references.
|
||||
* @param grammar the grammar to investigate
|
||||
* @returns the set of parser rules whose contributed types are used as type in cross-references
|
||||
*/
|
||||
export function getAllRulesUsedForCrossReferences(grammar) {
|
||||
const result = new Set();
|
||||
streamAllContents(grammar).forEach(node => {
|
||||
if (ast.isCrossReference(node)) {
|
||||
// the cross-reference refers directly to a parser rule (without "returns", without "infers")
|
||||
if (ast.isParserRule(node.type.ref)) {
|
||||
result.add(node.type.ref);
|
||||
}
|
||||
// the cross-reference refers to the explicitly inferred type of a parser rule
|
||||
if (ast.isInferredType(node.type.ref) && ast.isParserRule(node.type.ref.$container)) {
|
||||
result.add(node.type.ref.$container);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Determines the grammar expression used to parse a cross-reference (usually a reference to a terminal rule).
|
||||
* A cross-reference can declare this expression explicitly in the form `[Type : Terminal]`, but if `Terminal`
|
||||
* is omitted, this function attempts to infer it from the name of the referenced `Type` (using `findNameAssignment`).
|
||||
*
|
||||
* Returns the grammar expression used to parse the given cross-reference, or `undefined` if it is not declared
|
||||
* and cannot be inferred.
|
||||
*/
|
||||
export function getCrossReferenceTerminal(crossRef) {
|
||||
if (crossRef.terminal) {
|
||||
return crossRef.terminal;
|
||||
}
|
||||
else if (crossRef.type.ref) {
|
||||
const nameAssigment = findNameAssignment(crossRef.type.ref);
|
||||
return nameAssigment?.terminal;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Determines whether the given terminal rule represents a comment. This is true if the rule is marked
|
||||
* as `hidden` and it does not match white space. This means every hidden token (i.e. excluded from the AST)
|
||||
* that contains visible characters is considered a comment.
|
||||
*/
|
||||
export function isCommentTerminal(terminalRule) {
|
||||
return terminalRule.hidden && !isWhitespace(terminalRegex(terminalRule));
|
||||
}
|
||||
/**
|
||||
* Find all CST nodes within the given node that contribute to the specified property.
|
||||
*
|
||||
* @param node A CST node in which to look for property assignments. If this is undefined, the result is an empty array.
|
||||
* @param property A property name of the constructed AST node. If this is undefined, the result is an empty array.
|
||||
*/
|
||||
export function findNodesForProperty(node, property) {
|
||||
if (!node || !property) {
|
||||
return [];
|
||||
}
|
||||
return findNodesForPropertyInternal(node, property, node.astNode, true);
|
||||
}
|
||||
/**
|
||||
* Find a single CST node within the given node that contributes to the specified property.
|
||||
*
|
||||
* @param node A CST node in which to look for property assignments. If this is undefined, the result is `undefined`.
|
||||
* @param property A property name of the constructed AST node. If this is undefined, the result is `undefined`.
|
||||
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
|
||||
* specified index exceeds the number of assignments to the property, the last found node is returned. Otherwise,
|
||||
* the node with the specified index is returned.
|
||||
*/
|
||||
export function findNodeForProperty(node, property, index) {
|
||||
if (!node || !property) {
|
||||
return undefined;
|
||||
}
|
||||
const nodes = findNodesForPropertyInternal(node, property, node.astNode, true);
|
||||
if (nodes.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (index !== undefined) {
|
||||
index = Math.max(0, Math.min(index, nodes.length - 1));
|
||||
}
|
||||
else {
|
||||
index = 0;
|
||||
}
|
||||
return nodes[index];
|
||||
}
|
||||
function findNodesForPropertyInternal(node, property, element, first) {
|
||||
if (!first) {
|
||||
const nodeFeature = getContainerOfType(node.grammarSource, ast.isAssignment);
|
||||
if (nodeFeature && nodeFeature.feature === property) {
|
||||
return [node];
|
||||
}
|
||||
}
|
||||
if (isCompositeCstNode(node) && node.astNode === element) {
|
||||
return node.content.flatMap(e => findNodesForPropertyInternal(e, property, element, false));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* Find all CST nodes within the given node that correspond to the specified keyword.
|
||||
*
|
||||
* @param node A CST node in which to look for keywords. If this is undefined, the result is an empty array.
|
||||
* @param keyword A keyword as specified in the grammar.
|
||||
*/
|
||||
export function findNodesForKeyword(node, keyword) {
|
||||
if (!node) {
|
||||
return [];
|
||||
}
|
||||
return findNodesForKeywordInternal(node, keyword, node?.astNode);
|
||||
}
|
||||
/**
|
||||
* Find a single CST node within the given node that corresponds to the specified keyword.
|
||||
*
|
||||
* @param node A CST node in which to look for keywords. If this is undefined, the result is `undefined`.
|
||||
* @param keyword A keyword as specified in the grammar.
|
||||
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
|
||||
* specified index exceeds the number of keyword occurrences, the last found node is returned. Otherwise,
|
||||
* the node with the specified index is returned.
|
||||
*/
|
||||
export function findNodeForKeyword(node, keyword, index) {
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
const nodes = findNodesForKeywordInternal(node, keyword, node?.astNode);
|
||||
if (nodes.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (index !== undefined) {
|
||||
index = Math.max(0, Math.min(index, nodes.length - 1));
|
||||
}
|
||||
else {
|
||||
index = 0;
|
||||
}
|
||||
return nodes[index];
|
||||
}
|
||||
export function findNodesForKeywordInternal(node, keyword, element) {
|
||||
if (node.astNode !== element) {
|
||||
return [];
|
||||
}
|
||||
if (ast.isKeyword(node.grammarSource) && node.grammarSource.value === keyword) {
|
||||
return [node];
|
||||
}
|
||||
const treeIterator = streamCst(node).iterator();
|
||||
let result;
|
||||
const keywordNodes = [];
|
||||
do {
|
||||
result = treeIterator.next();
|
||||
if (!result.done) {
|
||||
const childNode = result.value;
|
||||
if (childNode.astNode === element) {
|
||||
if (ast.isKeyword(childNode.grammarSource) && childNode.grammarSource.value === keyword) {
|
||||
keywordNodes.push(childNode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
treeIterator.prune();
|
||||
}
|
||||
}
|
||||
} while (!result.done);
|
||||
return keywordNodes;
|
||||
}
|
||||
/**
|
||||
* If the given CST node was parsed in the context of a property assignment, the respective `Assignment` grammar
|
||||
* node is returned. If no assignment is found, the result is `undefined`.
|
||||
*
|
||||
* @param cstNode A CST node for which to find a property assignment.
|
||||
*/
|
||||
export function findAssignment(cstNode) {
|
||||
const astNode = cstNode.astNode;
|
||||
// Only search until the ast node of the parent cst node is no longer the original ast node
|
||||
// This would make us jump to a preceding rule call, which contains only unrelated assignments
|
||||
while (astNode === cstNode.container?.astNode) {
|
||||
const assignment = getContainerOfType(cstNode.grammarSource, ast.isAssignment);
|
||||
if (assignment) {
|
||||
return assignment;
|
||||
}
|
||||
cstNode = cstNode.container;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Find an assignment to the `name` property for the given grammar type. This requires the `type` to be inferred
|
||||
* from a parser rule, and that rule must contain an assignment to the `name` property. In all other cases,
|
||||
* this function returns `undefined`.
|
||||
*/
|
||||
export function findNameAssignment(type) {
|
||||
let startNode = type;
|
||||
if (ast.isInferredType(startNode)) {
|
||||
// for inferred types, the location to start searching for the name-assignment is different
|
||||
if (ast.isAction(startNode.$container)) {
|
||||
// a type which is explicitly inferred by an action: investigate the sibling of the Action node, i.e. start searching at the Action's parent
|
||||
startNode = startNode.$container.$container;
|
||||
}
|
||||
else if (ast.isAbstractParserRule(startNode.$container)) {
|
||||
// investigate the parser rule with the explicitly inferred type
|
||||
startNode = startNode.$container;
|
||||
}
|
||||
else {
|
||||
assertUnreachable(startNode.$container);
|
||||
}
|
||||
}
|
||||
return findNameAssignmentInternal(type, startNode, new Map());
|
||||
}
|
||||
function findNameAssignmentInternal(type, startNode, cache) {
|
||||
// the cache is only required to prevent infinite loops
|
||||
function go(node, refType) {
|
||||
let childAssignment = undefined;
|
||||
const parentAssignment = getContainerOfType(node, ast.isAssignment);
|
||||
// No parent assignment implies unassigned rule call
|
||||
if (!parentAssignment) {
|
||||
childAssignment = findNameAssignmentInternal(refType, refType, cache);
|
||||
}
|
||||
cache.set(type, childAssignment);
|
||||
return childAssignment;
|
||||
}
|
||||
if (cache.has(type)) {
|
||||
return cache.get(type);
|
||||
}
|
||||
cache.set(type, undefined);
|
||||
for (const node of streamAllContents(startNode)) {
|
||||
if (ast.isAssignment(node) && node.feature.toLowerCase() === 'name') {
|
||||
cache.set(type, node);
|
||||
return node;
|
||||
}
|
||||
else if (ast.isRuleCall(node) && ast.isParserRule(node.rule.ref)) {
|
||||
return go(node, node.rule.ref);
|
||||
}
|
||||
else if (ast.isSimpleType(node) && node.typeRef?.ref) {
|
||||
return go(node, node.typeRef.ref);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function getActionAtElement(element) {
|
||||
const parent = element.$container;
|
||||
if (ast.isGroup(parent)) {
|
||||
const elements = parent.elements;
|
||||
const index = elements.indexOf(element);
|
||||
for (let i = index - 1; i >= 0; i--) {
|
||||
const item = elements[i];
|
||||
if (ast.isAction(item)) {
|
||||
return item;
|
||||
}
|
||||
else {
|
||||
const action = streamAllContents(elements[i]).find(ast.isAction);
|
||||
if (action) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ast.isAbstractElement(parent)) {
|
||||
return getActionAtElement(parent);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
export function isOptionalCardinality(cardinality, element) {
|
||||
return cardinality === '?' || cardinality === '*' || (ast.isGroup(element) && Boolean(element.guardCondition));
|
||||
}
|
||||
export function isArrayCardinality(cardinality) {
|
||||
return cardinality === '*' || cardinality === '+';
|
||||
}
|
||||
export function isArrayOperator(operator) {
|
||||
return operator === '+=';
|
||||
}
|
||||
/**
|
||||
* Determines whether the given parser rule is a _data type rule_, meaning that it has a
|
||||
* primitive return type like `number`, `boolean`, etc.
|
||||
*/
|
||||
export function isDataTypeRule(rule) {
|
||||
return isDataTypeRuleInternal(rule, new Set());
|
||||
}
|
||||
function isDataTypeRuleInternal(rule, visited) {
|
||||
if (visited.has(rule)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
visited.add(rule);
|
||||
}
|
||||
for (const node of streamAllContents(rule)) {
|
||||
if (ast.isRuleCall(node)) {
|
||||
if (!node.rule.ref) {
|
||||
// RuleCall to unresolved rule. Don't assume `rule` is a DataType rule.
|
||||
return false;
|
||||
}
|
||||
if (ast.isParserRule(node.rule.ref) && !isDataTypeRuleInternal(node.rule.ref, visited)) {
|
||||
return false;
|
||||
}
|
||||
if (ast.isInfixRule(node.rule.ref)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ast.isAssignment(node)) {
|
||||
return false;
|
||||
}
|
||||
else if (ast.isAction(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return Boolean(rule.definition);
|
||||
}
|
||||
export function isDataType(type) {
|
||||
return isDataTypeInternal(type.type, new Set());
|
||||
}
|
||||
function isDataTypeInternal(type, visited) {
|
||||
if (visited.has(type)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
visited.add(type);
|
||||
}
|
||||
if (ast.isArrayType(type)) {
|
||||
return false;
|
||||
}
|
||||
else if (ast.isReferenceType(type)) {
|
||||
return false;
|
||||
}
|
||||
else if (ast.isUnionType(type)) {
|
||||
return type.types.every(e => isDataTypeInternal(e, visited));
|
||||
}
|
||||
else if (ast.isSimpleType(type)) {
|
||||
if (type.primitiveType !== undefined) {
|
||||
return true;
|
||||
}
|
||||
else if (type.stringType !== undefined) {
|
||||
return true;
|
||||
}
|
||||
else if (type.typeRef !== undefined) {
|
||||
const ref = type.typeRef.ref;
|
||||
if (ast.isType(ref)) {
|
||||
return isDataTypeInternal(ref.type, visited);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function getExplicitRuleType(rule) {
|
||||
if (ast.isTerminalRule(rule)) {
|
||||
return undefined;
|
||||
}
|
||||
if (rule.inferredType) {
|
||||
return rule.inferredType.name;
|
||||
}
|
||||
else if (rule.dataType) {
|
||||
return rule.dataType;
|
||||
}
|
||||
else if (rule.returnType) {
|
||||
const refType = rule.returnType.ref;
|
||||
if (refType) {
|
||||
return refType.name;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function getTypeName(type) {
|
||||
if (ast.isAbstractParserRule(type)) {
|
||||
return ast.isParserRule(type) && isDataTypeRule(type) ? type.name : getExplicitRuleType(type) ?? type.name;
|
||||
}
|
||||
else if (ast.isInterface(type) || ast.isType(type) || ast.isReturnType(type)) {
|
||||
return type.name;
|
||||
}
|
||||
else if (ast.isAction(type)) {
|
||||
const actionType = getActionType(type);
|
||||
if (actionType) {
|
||||
return actionType;
|
||||
}
|
||||
}
|
||||
else if (ast.isInferredType(type)) {
|
||||
return type.name;
|
||||
}
|
||||
throw new Error('Cannot get name of Unknown Type');
|
||||
}
|
||||
export function getActionType(action) {
|
||||
if (action.inferredType) {
|
||||
return action.inferredType.name;
|
||||
}
|
||||
else if (action.type?.ref) {
|
||||
return getTypeName(action.type.ref);
|
||||
}
|
||||
return undefined; // not inferring and not referencing a valid type
|
||||
}
|
||||
/**
|
||||
* This function is used at development time (for code generation and the internal type system) to get the type of the AST node produced by the given rule.
|
||||
* For data type rules, the name of the rule is returned,
|
||||
* e.g. "INT_value returns number: MY_INT;" returns "INT_value".
|
||||
* @param rule the given rule
|
||||
* @returns the name of the AST node type of the rule
|
||||
*/
|
||||
export function getRuleTypeName(rule) {
|
||||
if (ast.isTerminalRule(rule)) {
|
||||
return rule.type?.name ?? 'string';
|
||||
}
|
||||
else {
|
||||
return ast.isParserRule(rule) && isDataTypeRule(rule) ? rule.name : getExplicitRuleType(rule) ?? rule.name;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This function is used at runtime to get the actual type of the values produced by the given rule at runtime.
|
||||
* For data type rules, the name of the declared return type of the rule is returned (if any),
|
||||
* e.g. "INT_value returns number: MY_INT;" returns "number".
|
||||
* @param rule the given rule
|
||||
* @returns the name of the type of the produced values of the rule at runtime
|
||||
*/
|
||||
export function getRuleType(rule) {
|
||||
if (ast.isTerminalRule(rule)) {
|
||||
return rule.type?.name ?? 'string';
|
||||
}
|
||||
else {
|
||||
return getExplicitRuleType(rule) ?? rule.name;
|
||||
}
|
||||
}
|
||||
export function terminalRegex(terminalRule) {
|
||||
const flags = {
|
||||
s: false,
|
||||
i: false,
|
||||
u: false
|
||||
};
|
||||
const source = abstractElementToRegex(terminalRule.definition, flags);
|
||||
const flagText = Object.entries(flags).filter(([, value]) => value).map(([name]) => name).join('');
|
||||
return new RegExp(source, flagText);
|
||||
}
|
||||
// Using [\s\S]* allows to match everything, compared to . which doesn't match line terminators
|
||||
const WILDCARD = /[\s\S]/.source;
|
||||
function abstractElementToRegex(element, flags) {
|
||||
if (ast.isTerminalAlternatives(element)) {
|
||||
return terminalAlternativesToRegex(element);
|
||||
}
|
||||
else if (ast.isTerminalGroup(element)) {
|
||||
return terminalGroupToRegex(element);
|
||||
}
|
||||
else if (ast.isCharacterRange(element)) {
|
||||
return characterRangeToRegex(element);
|
||||
}
|
||||
else if (ast.isTerminalRuleCall(element)) {
|
||||
const rule = element.rule.ref;
|
||||
if (!rule) {
|
||||
throw new Error('Missing rule reference.');
|
||||
}
|
||||
return withCardinality(abstractElementToRegex(rule.definition), {
|
||||
cardinality: element.cardinality,
|
||||
lookahead: element.lookahead,
|
||||
parenthesized: element.parenthesized
|
||||
});
|
||||
}
|
||||
else if (ast.isNegatedToken(element)) {
|
||||
return negateTokenToRegex(element);
|
||||
}
|
||||
else if (ast.isUntilToken(element)) {
|
||||
return untilTokenToRegex(element);
|
||||
}
|
||||
else if (ast.isRegexToken(element)) {
|
||||
const lastSlash = element.regex.lastIndexOf('/');
|
||||
const source = element.regex.substring(1, lastSlash);
|
||||
const regexFlags = element.regex.substring(lastSlash + 1);
|
||||
if (flags) {
|
||||
flags.i = regexFlags.includes('i');
|
||||
flags.s = regexFlags.includes('s');
|
||||
flags.u = regexFlags.includes('u');
|
||||
}
|
||||
return withCardinality(source, {
|
||||
cardinality: element.cardinality,
|
||||
lookahead: element.lookahead,
|
||||
parenthesized: element.parenthesized,
|
||||
wrap: false
|
||||
});
|
||||
}
|
||||
else if (ast.isWildcard(element)) {
|
||||
return withCardinality(WILDCARD, {
|
||||
cardinality: element.cardinality,
|
||||
lookahead: element.lookahead,
|
||||
parenthesized: element.parenthesized
|
||||
});
|
||||
}
|
||||
else {
|
||||
throw new Error(`Invalid terminal element: ${element?.$type}, ${element?.$cstNode?.text}`);
|
||||
}
|
||||
}
|
||||
function terminalAlternativesToRegex(alternatives) {
|
||||
return withCardinality(alternatives.elements.map(e => abstractElementToRegex(e)).join('|'), {
|
||||
cardinality: alternatives.cardinality,
|
||||
lookahead: alternatives.lookahead,
|
||||
parenthesized: alternatives.parenthesized,
|
||||
wrap: false // wrapping is not required for top level alternatives, and nested alternatives are already parenthesized according to the grammar
|
||||
});
|
||||
}
|
||||
function terminalGroupToRegex(group) {
|
||||
return withCardinality(group.elements.map(e => abstractElementToRegex(e)).join(''), {
|
||||
cardinality: group.cardinality,
|
||||
lookahead: group.lookahead,
|
||||
parenthesized: group.parenthesized,
|
||||
wrap: false // wrapping is not required for top level group, and nested group are already parenthesized according to the grammar
|
||||
});
|
||||
}
|
||||
function untilTokenToRegex(until) {
|
||||
return withCardinality(`${WILDCARD}*?${abstractElementToRegex(until.terminal)}`, {
|
||||
cardinality: until.cardinality,
|
||||
lookahead: until.lookahead,
|
||||
parenthesized: until.parenthesized
|
||||
});
|
||||
}
|
||||
function negateTokenToRegex(negate) {
|
||||
return withCardinality(`(?!${abstractElementToRegex(negate.terminal)})${WILDCARD}*?`, {
|
||||
cardinality: negate.cardinality,
|
||||
lookahead: negate.lookahead,
|
||||
parenthesized: negate.parenthesized
|
||||
});
|
||||
}
|
||||
function characterRangeToRegex(range) {
|
||||
if (range.right) {
|
||||
return withCardinality(`[${keywordToRegex(range.left)}-${keywordToRegex(range.right)}]`, {
|
||||
cardinality: range.cardinality,
|
||||
lookahead: range.lookahead,
|
||||
parenthesized: range.parenthesized,
|
||||
wrap: false
|
||||
});
|
||||
}
|
||||
return withCardinality(keywordToRegex(range.left), {
|
||||
cardinality: range.cardinality,
|
||||
lookahead: range.lookahead,
|
||||
parenthesized: range.parenthesized,
|
||||
wrap: false
|
||||
});
|
||||
}
|
||||
function keywordToRegex(keyword) {
|
||||
return escapeRegExp(keyword.value);
|
||||
}
|
||||
function withCardinality(regex, options) {
|
||||
if (options.parenthesized || options.lookahead || options.wrap !== false) {
|
||||
const groupConfig = options.lookahead ?? (options.parenthesized ? '' : '?:');
|
||||
regex = `(${groupConfig}${regex})`;
|
||||
}
|
||||
if (options.cardinality) {
|
||||
return `${regex}${options.cardinality}`;
|
||||
}
|
||||
return regex;
|
||||
}
|
||||
//# sourceMappingURL=grammar-utils.js.map
|
||||
1
frontend/node_modules/langium/lib/utils/promise-utils.d.ts.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/promise-utils.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"promise-utils.d.ts","sourceRoot":"","sources":["../../src/utils/promise-utils.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,iBAAiB,EAA2B,KAAK,+BAA+B,EAAE,MAAM,0BAA0B,CAAC;AAE5H,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAE5C;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAU7C;AAKD;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,+BAA+B,CAG1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE1D;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,eAA+B,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,OAAO,kBAAkB,CAEnF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/E;AAED;;;GAGG;AACH,qBAAa,QAAQ,CAAC,CAAC,GAAG,IAAI;IAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAEhC,OAAO,aASJ;CACN"}
|
||||
99
frontend/node_modules/langium/lib/utils/promise-utils.js
generated
vendored
Normal file
99
frontend/node_modules/langium/lib/utils/promise-utils.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/******************************************************************************
|
||||
* 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, CancellationTokenSource } from '../utils/cancellation.js';
|
||||
/**
|
||||
* Delays the execution of the current code to the next tick of the event loop.
|
||||
* Don't call this method directly in a tight loop to prevent too many promises from being created.
|
||||
*/
|
||||
export function delayNextTick() {
|
||||
return new Promise(resolve => {
|
||||
// In case we are running in a non-node environment, `setImmediate` isn't available.
|
||||
// Using `setTimeout` of the browser API accomplishes the same result.
|
||||
if (typeof setImmediate === 'undefined') {
|
||||
setTimeout(resolve, 0);
|
||||
}
|
||||
else {
|
||||
setImmediate(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
let lastTick = 0;
|
||||
let globalInterruptionPeriod = 10;
|
||||
/**
|
||||
* Reset the global interruption period and create a cancellation token source.
|
||||
*/
|
||||
export function startCancelableOperation() {
|
||||
lastTick = performance.now();
|
||||
return new CancellationTokenSource();
|
||||
}
|
||||
/**
|
||||
* Change the period duration for `interruptAndCheck` to the given number of milliseconds.
|
||||
* The default value is 10ms.
|
||||
*/
|
||||
export function setInterruptionPeriod(period) {
|
||||
globalInterruptionPeriod = period;
|
||||
}
|
||||
/**
|
||||
* This symbol may be thrown in an asynchronous context by any Langium service that receives
|
||||
* a `CancellationToken`. This means that the promise returned by such a service is rejected with
|
||||
* this symbol as rejection reason.
|
||||
*/
|
||||
export const OperationCancelled = Symbol('OperationCancelled');
|
||||
/**
|
||||
* Use this in a `catch` block to check whether the thrown object indicates that the operation
|
||||
* has been cancelled.
|
||||
*/
|
||||
export function isOperationCancelled(err) {
|
||||
return err === OperationCancelled;
|
||||
}
|
||||
/**
|
||||
* This function does two things:
|
||||
* 1. Check the elapsed time since the last call to this function or to `startCancelableOperation`. If the predefined
|
||||
* period (configured with `setInterruptionPeriod`) is exceeded, execution is delayed with `delayNextTick`.
|
||||
* 2. If the predefined period is not met yet or execution is resumed after an interruption, the given cancellation
|
||||
* token is checked, and if cancellation is requested, `OperationCanceled` is thrown.
|
||||
*
|
||||
* All services in Langium that receive a `CancellationToken` may potentially call this function, so the
|
||||
* `CancellationToken` must be caught (with an `async` try-catch block or a `catch` callback attached to
|
||||
* the promise) to avoid that event being exposed as an error.
|
||||
*/
|
||||
export async function interruptAndCheck(token) {
|
||||
if (token === CancellationToken.None) {
|
||||
// Early exit in case cancellation was disabled by the caller
|
||||
return;
|
||||
}
|
||||
const current = performance.now();
|
||||
if (current - lastTick >= globalInterruptionPeriod) {
|
||||
lastTick = current;
|
||||
await delayNextTick();
|
||||
// prevent calling delayNextTick every iteration of loop
|
||||
// where delayNextTick takes up the majority or all of the
|
||||
// globalInterruptionPeriod itself
|
||||
lastTick = performance.now();
|
||||
}
|
||||
if (token.isCancellationRequested) {
|
||||
throw OperationCancelled;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Simple implementation of the deferred pattern.
|
||||
* An object that exposes a promise and functions to resolve and reject it.
|
||||
*/
|
||||
export class Deferred {
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = (arg) => {
|
||||
resolve(arg);
|
||||
return this;
|
||||
};
|
||||
this.reject = (err) => {
|
||||
reject(err);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=promise-utils.js.map
|
||||
294
frontend/node_modules/langium/lib/utils/regexp-utils.js
generated
vendored
Normal file
294
frontend/node_modules/langium/lib/utils/regexp-utils.js
generated
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
/******************************************************************************
|
||||
* 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 { RegExpParser, BaseRegExpVisitor } from '@chevrotain/regexp-to-ast';
|
||||
export const NEWLINE_REGEXP = /\r?\n/gm;
|
||||
const regexpParser = new RegExpParser();
|
||||
/**
|
||||
* This class is in charge of heuristically identifying start/end tokens of terminals.
|
||||
*
|
||||
* The way this works is by doing the following:
|
||||
* 1. Traverse the regular expression in the "start state"
|
||||
* 2. Add any encountered sets/single characters to the "start regexp"
|
||||
* 3. Once we encounter any variable-length content (i.e. with quantifiers such as +/?/*), we enter the "end state"
|
||||
* 4. In the end state, any sets/single characters are added to an "end stack".
|
||||
* 5. If we re-encounter any variable-length content we reset the end stack
|
||||
* 6. We continue visiting the regex until the end, reseting the end stack and rebuilding it as necessary
|
||||
*
|
||||
* After traversing a regular expression the `startRegexp/endRegexp` properties allow access to the stored start/end of the terminal
|
||||
*/
|
||||
class TerminalRegExpVisitor extends BaseRegExpVisitor {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.isStarting = true;
|
||||
this.endRegexpStack = [];
|
||||
this.multiline = false;
|
||||
}
|
||||
get endRegex() {
|
||||
return this.endRegexpStack.join('');
|
||||
}
|
||||
reset(regex) {
|
||||
this.multiline = false;
|
||||
this.regex = regex;
|
||||
this.startRegexp = '';
|
||||
this.isStarting = true;
|
||||
this.endRegexpStack = [];
|
||||
}
|
||||
visitGroup(node) {
|
||||
if (node.quantifier) {
|
||||
this.isStarting = false;
|
||||
this.endRegexpStack = [];
|
||||
}
|
||||
}
|
||||
visitCharacter(node) {
|
||||
const char = String.fromCharCode(node.value);
|
||||
if (!this.multiline && char === '\n') {
|
||||
this.multiline = true;
|
||||
}
|
||||
if (node.quantifier) {
|
||||
this.isStarting = false;
|
||||
this.endRegexpStack = [];
|
||||
}
|
||||
else {
|
||||
const escapedChar = escapeRegExp(char);
|
||||
this.endRegexpStack.push(escapedChar);
|
||||
if (this.isStarting) {
|
||||
this.startRegexp += escapedChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
visitSet(node) {
|
||||
if (!this.multiline) {
|
||||
const set = this.regex.substring(node.loc.begin, node.loc.end);
|
||||
const regex = new RegExp(set);
|
||||
this.multiline = Boolean('\n'.match(regex));
|
||||
}
|
||||
if (node.quantifier) {
|
||||
this.isStarting = false;
|
||||
this.endRegexpStack = [];
|
||||
}
|
||||
else {
|
||||
const set = this.regex.substring(node.loc.begin, node.loc.end);
|
||||
this.endRegexpStack.push(set);
|
||||
if (this.isStarting) {
|
||||
this.startRegexp += set;
|
||||
}
|
||||
}
|
||||
}
|
||||
visitChildren(node) {
|
||||
if (node.type === 'Group') {
|
||||
// Ignore children of groups with quantifier (+/*/?)
|
||||
// These groups are unrelated to start/end tokens of terminals
|
||||
const group = node;
|
||||
if (group.quantifier) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.visitChildren(node);
|
||||
}
|
||||
}
|
||||
const visitor = new TerminalRegExpVisitor();
|
||||
export function getTerminalParts(regexp) {
|
||||
try {
|
||||
if (typeof regexp !== 'string') {
|
||||
regexp = regexp.source;
|
||||
}
|
||||
regexp = `/${regexp}/`;
|
||||
const pattern = regexpParser.pattern(regexp);
|
||||
const parts = [];
|
||||
for (const alternative of pattern.value.value) {
|
||||
visitor.reset(regexp);
|
||||
visitor.visit(alternative);
|
||||
parts.push({
|
||||
start: visitor.startRegexp,
|
||||
end: visitor.endRegex
|
||||
});
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
export function isMultilineComment(regexp) {
|
||||
try {
|
||||
if (typeof regexp === 'string') {
|
||||
regexp = new RegExp(regexp);
|
||||
}
|
||||
regexp = regexp.toString();
|
||||
visitor.reset(regexp);
|
||||
// Parsing the pattern might fail (since it's user code)
|
||||
visitor.visit(regexpParser.pattern(regexp));
|
||||
return visitor.multiline;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A set of all characters that are considered whitespace by the '\s' RegExp character class.
|
||||
* Taken from [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes).
|
||||
*/
|
||||
export const whitespaceCharacters = ('\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007' +
|
||||
'\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff').split('');
|
||||
export function isWhitespace(value) {
|
||||
const regexp = typeof value === 'string' ? new RegExp(value) : value;
|
||||
return whitespaceCharacters.some((ws) => regexp.test(ws));
|
||||
}
|
||||
export function escapeRegExp(value) {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
/**
|
||||
* Determines whether the given input has a partial match with the specified regex.
|
||||
* @param regex The regex to partially match against
|
||||
* @param input The input string
|
||||
* @returns Whether any match exists.
|
||||
*/
|
||||
export function partialMatches(regex, input) {
|
||||
const partial = partialRegExp(regex);
|
||||
const match = input.match(partial);
|
||||
return !!match && match[0].length > 0;
|
||||
}
|
||||
/**
|
||||
* Builds a partial regex from the input regex. A partial regex is able to match incomplete input strings. E.g.
|
||||
* a partial regex constructed from `/ab/` is able to match the string `a` without needing a following `b` character. However it won't match `b` alone.
|
||||
* @param regex The input regex to be converted.
|
||||
* @returns A partial regex constructed from the input regex.
|
||||
*/
|
||||
export function partialRegExp(regex) {
|
||||
if (typeof regex === 'string') {
|
||||
regex = new RegExp(regex);
|
||||
}
|
||||
const re = regex, source = regex.source;
|
||||
let i = 0;
|
||||
function process() {
|
||||
let result = '', tmp;
|
||||
function appendRaw(nbChars) {
|
||||
result += source.substr(i, nbChars);
|
||||
i += nbChars;
|
||||
}
|
||||
function appendOptional(nbChars) {
|
||||
result += '(?:' + source.substr(i, nbChars) + '|$)';
|
||||
i += nbChars;
|
||||
}
|
||||
while (i < source.length) {
|
||||
switch (source[i]) {
|
||||
case '\\':
|
||||
switch (source[i + 1]) {
|
||||
case 'c':
|
||||
appendOptional(3);
|
||||
break;
|
||||
case 'x':
|
||||
appendOptional(4);
|
||||
break;
|
||||
case 'u':
|
||||
if (re.unicode) {
|
||||
if (source[i + 2] === '{') {
|
||||
appendOptional(source.indexOf('}', i) - i + 1);
|
||||
}
|
||||
else {
|
||||
appendOptional(6);
|
||||
}
|
||||
}
|
||||
else {
|
||||
appendOptional(2);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
if (re.unicode) {
|
||||
appendOptional(source.indexOf('}', i) - i + 1);
|
||||
}
|
||||
else {
|
||||
appendOptional(2);
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
appendOptional(source.indexOf('>', i) - i + 1);
|
||||
break;
|
||||
default:
|
||||
appendOptional(2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
tmp = /\[(?:\\.|.)*?\]/g;
|
||||
tmp.lastIndex = i;
|
||||
tmp = tmp.exec(source) || [];
|
||||
appendOptional(tmp[0].length);
|
||||
break;
|
||||
case '|':
|
||||
case '^':
|
||||
case '$':
|
||||
case '*':
|
||||
case '+':
|
||||
case '?':
|
||||
appendRaw(1);
|
||||
break;
|
||||
case '{':
|
||||
tmp = /\{\d+,?\d*\}/g;
|
||||
tmp.lastIndex = i;
|
||||
tmp = tmp.exec(source);
|
||||
if (tmp) {
|
||||
appendRaw(tmp[0].length);
|
||||
}
|
||||
else {
|
||||
appendOptional(1);
|
||||
}
|
||||
break;
|
||||
case '(':
|
||||
if (source[i + 1] === '?') {
|
||||
switch (source[i + 2]) {
|
||||
case ':':
|
||||
result += '(?:';
|
||||
i += 3;
|
||||
result += process() + '|$)';
|
||||
break;
|
||||
case '=':
|
||||
result += '(?=';
|
||||
i += 3;
|
||||
result += process() + ')';
|
||||
break;
|
||||
case '!':
|
||||
tmp = i;
|
||||
i += 3;
|
||||
process();
|
||||
result += source.substr(tmp, i - tmp);
|
||||
break;
|
||||
case '<':
|
||||
switch (source[i + 3]) {
|
||||
case '=':
|
||||
case '!':
|
||||
tmp = i;
|
||||
i += 4;
|
||||
process();
|
||||
result += source.substr(tmp, i - tmp);
|
||||
break;
|
||||
default:
|
||||
appendRaw(source.indexOf('>', i) - i + 1);
|
||||
result += process() + '|$)';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
appendRaw(1);
|
||||
result += process() + '|$)';
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
++i;
|
||||
return result;
|
||||
default:
|
||||
appendOptional(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return new RegExp(process(), regex.flags);
|
||||
}
|
||||
//# sourceMappingURL=regexp-utils.js.map
|
||||
510
frontend/node_modules/langium/lib/utils/stream.js
generated
vendored
Normal file
510
frontend/node_modules/langium/lib/utils/stream.js
generated
vendored
Normal file
@@ -0,0 +1,510 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
/**
|
||||
* The default implementation of `Stream` works with two input functions:
|
||||
* - The first function creates the initial state of an iteration.
|
||||
* - The second function gets the current state as argument and returns an `IteratorResult`.
|
||||
*/
|
||||
export class StreamImpl {
|
||||
constructor(startFn, nextFn) {
|
||||
this.startFn = startFn;
|
||||
this.nextFn = nextFn;
|
||||
}
|
||||
iterator() {
|
||||
const iterator = {
|
||||
state: this.startFn(),
|
||||
next: () => this.nextFn(iterator.state),
|
||||
[Symbol.iterator]: () => iterator
|
||||
};
|
||||
return iterator;
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.iterator();
|
||||
}
|
||||
isEmpty() {
|
||||
const iterator = this.iterator();
|
||||
return Boolean(iterator.next().done);
|
||||
}
|
||||
count() {
|
||||
const iterator = this.iterator();
|
||||
let count = 0;
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
count++;
|
||||
next = iterator.next();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
toArray() {
|
||||
const result = [];
|
||||
const iterator = this.iterator();
|
||||
let next;
|
||||
do {
|
||||
next = iterator.next();
|
||||
if (next.value !== undefined) {
|
||||
result.push(next.value);
|
||||
}
|
||||
} while (!next.done);
|
||||
return result;
|
||||
}
|
||||
toSet() {
|
||||
return new Set(this);
|
||||
}
|
||||
toMap(keyFn, valueFn) {
|
||||
const entryStream = this.map(element => [
|
||||
keyFn ? keyFn(element) : element,
|
||||
valueFn ? valueFn(element) : element
|
||||
]);
|
||||
return new Map(entryStream);
|
||||
}
|
||||
toString() {
|
||||
return this.join();
|
||||
}
|
||||
concat(other) {
|
||||
return new StreamImpl(() => ({ first: this.startFn(), firstDone: false, iterator: other[Symbol.iterator]() }), state => {
|
||||
let result;
|
||||
if (!state.firstDone) {
|
||||
do {
|
||||
result = this.nextFn(state.first);
|
||||
if (!result.done) {
|
||||
return result;
|
||||
}
|
||||
} while (!result.done);
|
||||
state.firstDone = true;
|
||||
}
|
||||
do {
|
||||
result = state.iterator.next();
|
||||
if (!result.done) {
|
||||
return result;
|
||||
}
|
||||
} while (!result.done);
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
join(separator = ',') {
|
||||
const iterator = this.iterator();
|
||||
let value = '';
|
||||
let result;
|
||||
let addSeparator = false;
|
||||
do {
|
||||
result = iterator.next();
|
||||
if (!result.done) {
|
||||
if (addSeparator) {
|
||||
value += separator;
|
||||
}
|
||||
value += toString(result.value);
|
||||
}
|
||||
addSeparator = true;
|
||||
} while (!result.done);
|
||||
return value;
|
||||
}
|
||||
indexOf(searchElement, fromIndex = 0) {
|
||||
const iterator = this.iterator();
|
||||
let index = 0;
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (index >= fromIndex && next.value === searchElement) {
|
||||
return index;
|
||||
}
|
||||
next = iterator.next();
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
every(predicate) {
|
||||
const iterator = this.iterator();
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (!predicate(next.value)) {
|
||||
return false;
|
||||
}
|
||||
next = iterator.next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
some(predicate) {
|
||||
const iterator = this.iterator();
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (predicate(next.value)) {
|
||||
return true;
|
||||
}
|
||||
next = iterator.next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
forEach(callbackfn) {
|
||||
const iterator = this.iterator();
|
||||
let index = 0;
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
callbackfn(next.value, index);
|
||||
next = iterator.next();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
map(callbackfn) {
|
||||
return new StreamImpl(this.startFn, (state) => {
|
||||
const { done, value } = this.nextFn(state);
|
||||
if (done) {
|
||||
return DONE_RESULT;
|
||||
}
|
||||
else {
|
||||
return { done: false, value: callbackfn(value) };
|
||||
}
|
||||
});
|
||||
}
|
||||
filter(predicate) {
|
||||
return new StreamImpl(this.startFn, state => {
|
||||
let result;
|
||||
do {
|
||||
result = this.nextFn(state);
|
||||
if (!result.done && predicate(result.value)) {
|
||||
return result;
|
||||
}
|
||||
} while (!result.done);
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
nonNullable() {
|
||||
return this.filter(e => e !== undefined && e !== null);
|
||||
}
|
||||
reduce(callbackfn, initialValue) {
|
||||
const iterator = this.iterator();
|
||||
let previousValue = initialValue;
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (previousValue === undefined) {
|
||||
previousValue = next.value;
|
||||
}
|
||||
else {
|
||||
previousValue = callbackfn(previousValue, next.value);
|
||||
}
|
||||
next = iterator.next();
|
||||
}
|
||||
return previousValue;
|
||||
}
|
||||
reduceRight(callbackfn, initialValue) {
|
||||
return this.recursiveReduce(this.iterator(), callbackfn, initialValue);
|
||||
}
|
||||
recursiveReduce(iterator, callbackfn, initialValue) {
|
||||
const next = iterator.next();
|
||||
if (next.done) {
|
||||
return initialValue;
|
||||
}
|
||||
const previousValue = this.recursiveReduce(iterator, callbackfn, initialValue);
|
||||
if (previousValue === undefined) {
|
||||
return next.value;
|
||||
}
|
||||
return callbackfn(previousValue, next.value);
|
||||
}
|
||||
find(predicate) {
|
||||
const iterator = this.iterator();
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (predicate(next.value)) {
|
||||
return next.value;
|
||||
}
|
||||
next = iterator.next();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
findIndex(predicate) {
|
||||
const iterator = this.iterator();
|
||||
let index = 0;
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (predicate(next.value)) {
|
||||
return index;
|
||||
}
|
||||
next = iterator.next();
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
includes(searchElement) {
|
||||
const iterator = this.iterator();
|
||||
let next = iterator.next();
|
||||
while (!next.done) {
|
||||
if (next.value === searchElement) {
|
||||
return true;
|
||||
}
|
||||
next = iterator.next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
flatMap(callbackfn) {
|
||||
return new StreamImpl(() => ({ this: this.startFn() }), (state) => {
|
||||
do {
|
||||
if (state.iterator) {
|
||||
const next = state.iterator.next();
|
||||
if (next.done) {
|
||||
state.iterator = undefined;
|
||||
}
|
||||
else {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
const { done, value } = this.nextFn(state.this);
|
||||
if (!done) {
|
||||
const mapped = callbackfn(value);
|
||||
if (isIterable(mapped)) {
|
||||
state.iterator = mapped[Symbol.iterator]();
|
||||
}
|
||||
else {
|
||||
return { done: false, value: mapped };
|
||||
}
|
||||
}
|
||||
} while (state.iterator);
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
flat(depth) {
|
||||
if (depth === undefined) {
|
||||
depth = 1;
|
||||
}
|
||||
if (depth <= 0) {
|
||||
return this;
|
||||
}
|
||||
const stream = depth > 1 ? this.flat(depth - 1) : this;
|
||||
return new StreamImpl(() => ({ this: stream.startFn() }), (state) => {
|
||||
do {
|
||||
if (state.iterator) {
|
||||
const next = state.iterator.next();
|
||||
if (next.done) {
|
||||
state.iterator = undefined;
|
||||
}
|
||||
else {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
const { done, value } = stream.nextFn(state.this);
|
||||
if (!done) {
|
||||
if (isIterable(value)) {
|
||||
state.iterator = value[Symbol.iterator]();
|
||||
}
|
||||
else {
|
||||
return { done: false, value: value };
|
||||
}
|
||||
}
|
||||
} while (state.iterator);
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
head() {
|
||||
const iterator = this.iterator();
|
||||
const result = iterator.next();
|
||||
if (result.done) {
|
||||
return undefined;
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
tail(skipCount = 1) {
|
||||
return new StreamImpl(() => {
|
||||
const state = this.startFn();
|
||||
for (let i = 0; i < skipCount; i++) {
|
||||
const next = this.nextFn(state);
|
||||
if (next.done) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}, this.nextFn);
|
||||
}
|
||||
limit(maxSize) {
|
||||
return new StreamImpl(() => ({ size: 0, state: this.startFn() }), state => {
|
||||
state.size++;
|
||||
if (state.size > maxSize) {
|
||||
return DONE_RESULT;
|
||||
}
|
||||
return this.nextFn(state.state);
|
||||
});
|
||||
}
|
||||
distinct(by) {
|
||||
return new StreamImpl(() => ({ set: new Set(), internalState: this.startFn() }), state => {
|
||||
let result;
|
||||
do {
|
||||
result = this.nextFn(state.internalState);
|
||||
if (!result.done) {
|
||||
const value = by ? by(result.value) : result.value;
|
||||
if (!state.set.has(value)) {
|
||||
state.set.add(value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} while (!result.done);
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
exclude(other, key) {
|
||||
const otherKeySet = new Set();
|
||||
for (const item of other) {
|
||||
const value = key ? key(item) : item;
|
||||
otherKeySet.add(value);
|
||||
}
|
||||
return this.filter(e => {
|
||||
const ownKey = key ? key(e) : e;
|
||||
return !otherKeySet.has(ownKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
function toString(item) {
|
||||
if (typeof item === 'string') {
|
||||
return item;
|
||||
}
|
||||
if (typeof item === 'undefined') {
|
||||
return 'undefined';
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if (typeof item.toString === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return item.toString();
|
||||
}
|
||||
return Object.prototype.toString.call(item);
|
||||
}
|
||||
function isIterable(obj) {
|
||||
return !!obj && typeof obj[Symbol.iterator] === 'function';
|
||||
}
|
||||
/**
|
||||
* An empty stream of any type.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const EMPTY_STREAM = new StreamImpl(() => undefined, () => DONE_RESULT);
|
||||
/**
|
||||
* Use this `IteratorResult` when implementing a `StreamImpl` to indicate that there are no more elements in the stream.
|
||||
*/
|
||||
export const DONE_RESULT = Object.freeze({ done: true, value: undefined });
|
||||
/**
|
||||
* Create a stream from one or more iterables or array-likes.
|
||||
*/
|
||||
export function stream(...collections) {
|
||||
if (collections.length === 1) {
|
||||
const collection = collections[0];
|
||||
if (collection instanceof StreamImpl) {
|
||||
return collection;
|
||||
}
|
||||
if (isIterable(collection)) {
|
||||
return new StreamImpl(() => collection[Symbol.iterator](), (iterator) => iterator.next());
|
||||
}
|
||||
if (typeof collection.length === 'number') {
|
||||
return new StreamImpl(() => ({ index: 0 }), (state) => {
|
||||
if (state.index < collection.length) {
|
||||
return { done: false, value: collection[state.index++] };
|
||||
}
|
||||
else {
|
||||
return DONE_RESULT;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (collections.length > 1) {
|
||||
return new StreamImpl(() => ({ collIndex: 0, arrIndex: 0 }), (state) => {
|
||||
do {
|
||||
if (state.iterator) {
|
||||
const next = state.iterator.next();
|
||||
if (!next.done) {
|
||||
return next;
|
||||
}
|
||||
state.iterator = undefined;
|
||||
}
|
||||
if (state.array) {
|
||||
if (state.arrIndex < state.array.length) {
|
||||
return { done: false, value: state.array[state.arrIndex++] };
|
||||
}
|
||||
state.array = undefined;
|
||||
state.arrIndex = 0;
|
||||
}
|
||||
if (state.collIndex < collections.length) {
|
||||
const collection = collections[state.collIndex++];
|
||||
if (isIterable(collection)) {
|
||||
state.iterator = collection[Symbol.iterator]();
|
||||
}
|
||||
else if (collection && typeof collection.length === 'number') {
|
||||
state.array = collection;
|
||||
}
|
||||
}
|
||||
} while (state.iterator || state.array || state.collIndex < collections.length);
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
return EMPTY_STREAM;
|
||||
}
|
||||
/**
|
||||
* The default implementation of `TreeStream` takes a root element and a function that computes the
|
||||
* children of its argument. Whether the root node included in the stream is controlled with the
|
||||
* `includeRoot` option, which defaults to `false`.
|
||||
*/
|
||||
export class TreeStreamImpl extends StreamImpl {
|
||||
constructor(root, children, options) {
|
||||
super(() => ({
|
||||
iterators: options?.includeRoot ? [[root][Symbol.iterator]()] : [children(root)[Symbol.iterator]()],
|
||||
pruned: false
|
||||
}), state => {
|
||||
if (state.pruned) {
|
||||
state.iterators.pop();
|
||||
state.pruned = false;
|
||||
}
|
||||
while (state.iterators.length > 0) {
|
||||
const iterator = state.iterators[state.iterators.length - 1];
|
||||
const next = iterator.next();
|
||||
if (next.done) {
|
||||
state.iterators.pop();
|
||||
}
|
||||
else {
|
||||
state.iterators.push(children(next.value)[Symbol.iterator]());
|
||||
return next;
|
||||
}
|
||||
}
|
||||
return DONE_RESULT;
|
||||
});
|
||||
}
|
||||
iterator() {
|
||||
const iterator = {
|
||||
state: this.startFn(),
|
||||
next: () => this.nextFn(iterator.state),
|
||||
prune: () => {
|
||||
iterator.state.pruned = true;
|
||||
},
|
||||
[Symbol.iterator]: () => iterator
|
||||
};
|
||||
return iterator;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A set of utility functions that reduce a stream to a single value.
|
||||
*/
|
||||
export var Reduction;
|
||||
(function (Reduction) {
|
||||
/**
|
||||
* Compute the sum of a number stream.
|
||||
*/
|
||||
function sum(stream) {
|
||||
return stream.reduce((a, b) => a + b, 0);
|
||||
}
|
||||
Reduction.sum = sum;
|
||||
/**
|
||||
* Compute the product of a number stream.
|
||||
*/
|
||||
function product(stream) {
|
||||
return stream.reduce((a, b) => a * b, 0);
|
||||
}
|
||||
Reduction.product = product;
|
||||
/**
|
||||
* Compute the minimum of a number stream. Returns `undefined` if the stream is empty.
|
||||
*/
|
||||
function min(stream) {
|
||||
return stream.reduce((a, b) => Math.min(a, b));
|
||||
}
|
||||
Reduction.min = min;
|
||||
/**
|
||||
* Compute the maximum of a number stream. Returns `undefined` if the stream is empty.
|
||||
*/
|
||||
function max(stream) {
|
||||
return stream.reduce((a, b) => Math.max(a, b));
|
||||
}
|
||||
Reduction.max = max;
|
||||
})(Reduction || (Reduction = {}));
|
||||
//# sourceMappingURL=stream.js.map
|
||||
55
frontend/node_modules/langium/lib/utils/uri-utils.d.ts
generated
vendored
Normal file
55
frontend/node_modules/langium/lib/utils/uri-utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/******************************************************************************
|
||||
* Copyright 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 { URI, Utils } from 'vscode-uri';
|
||||
export { URI };
|
||||
export declare namespace UriUtils {
|
||||
const basename: typeof Utils.basename;
|
||||
const dirname: typeof Utils.dirname;
|
||||
const extname: typeof Utils.extname;
|
||||
const joinPath: typeof Utils.joinPath;
|
||||
const resolvePath: typeof Utils.resolvePath;
|
||||
function equals(a?: URI | string, b?: URI | string): boolean;
|
||||
function relative(from: URI | string, to: URI | string): string;
|
||||
function normalize(uri: URI | string): string;
|
||||
function contains(parent: URI | string, child: URI | string): boolean;
|
||||
}
|
||||
interface InternalUriTrieNode<T> {
|
||||
name: string;
|
||||
children: Map<string, InternalUriTrieNode<T>>;
|
||||
parent?: InternalUriTrieNode<T>;
|
||||
element?: T;
|
||||
}
|
||||
export interface UriTrieNode<T> {
|
||||
name: string;
|
||||
uri: string;
|
||||
element?: T;
|
||||
}
|
||||
/**
|
||||
* A trie structure for URIs. It allows to insert, delete and find elements by their URI.
|
||||
* More specifically, it allows to efficiently find all elements that are children of a given URI.
|
||||
*
|
||||
* Unlike a regular trie, this implementation uses the name of the URI segments as keys.
|
||||
*
|
||||
* @see {@link https://en.wikipedia.org/wiki/Trie}
|
||||
*/
|
||||
export declare class UriTrie<T> {
|
||||
protected readonly root: InternalUriTrieNode<T>;
|
||||
protected normalizeUri(uri: URI | string): string;
|
||||
clear(): void;
|
||||
insert(uri: URI | string, element: T): void;
|
||||
delete(uri: URI | string): void;
|
||||
has(uri: URI | string): boolean;
|
||||
hasNode(uri: URI | string): boolean;
|
||||
find(uri: URI | string): T | undefined;
|
||||
findNode(uri: URI | string): UriTrieNode<T> | undefined;
|
||||
findChildren(uri: URI | string): Array<UriTrieNode<T>>;
|
||||
all(): T[];
|
||||
findAll(prefix: URI | string): T[];
|
||||
protected getNode(uri: string, create: true): InternalUriTrieNode<T>;
|
||||
protected getNode(uri: string, create: false): InternalUriTrieNode<T> | undefined;
|
||||
protected collectValues(node: InternalUriTrieNode<T>): T[];
|
||||
}
|
||||
//# sourceMappingURL=uri-utils.d.ts.map
|
||||
1
frontend/node_modules/langium/lib/utils/uri-utils.d.ts.map
generated
vendored
Normal file
1
frontend/node_modules/langium/lib/utils/uri-utils.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"uri-utils.d.ts","sourceRoot":"","sources":["../../src/utils/uri-utils.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,GAAG,EAAE,CAAC;AAEf,yBAAiB,QAAQ,CAAC;IAEf,MAAM,QAAQ,uBAAiB,CAAC;IAChC,MAAM,OAAO,sBAAgB,CAAC;IAC9B,MAAM,OAAO,sBAAgB,CAAC;IAC9B,MAAM,QAAQ,uBAAiB,CAAC;IAChC,MAAM,WAAW,0BAAoB,CAAC;IAI7C,SAAgB,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAElE;IAED,SAAgB,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM,CA6BrE;IAED,SAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM,CAEnD;IAED,SAAgB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAwB3E;CAEJ;AAED,UAAU,mBAAmB,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAEhC,OAAO,CAAC,EAAE,CAAC,CAAC;CACf;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,CAAC,CAAC;CACf;AAED;;;;;;;GAOG;AACH,qBAAa,OAAO,CAAC,CAAC;IAElB,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAqC;IAEpF,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM;IAIjD,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IAK3C,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI;IAO/B,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO;IAI/B,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO;IAInC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,SAAS;IAItC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS;IAavD,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAatD,GAAG,IAAI,CAAC,EAAE;IAIV,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE;IAQlC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,mBAAmB,CAAC,CAAC,CAAC;IACpE,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,SAAS;IA2BjF,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;CAW7D"}
|
||||
Reference in New Issue
Block a user