+12
@@ -0,0 +1,12 @@
|
||||
/******************************************************************************
|
||||
* 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 type { AstReflection } from '../syntax-tree.js';
|
||||
import type { LangiumCoreServices } from '../index.js';
|
||||
import type { Grammar } from '../languages/generated/ast.js';
|
||||
import type { AstTypes } from './type-system/type-collector/types.js';
|
||||
export declare function interpretAstReflection(astTypes: AstTypes): AstReflection;
|
||||
export declare function interpretAstReflection(grammar: Grammar, services?: LangiumCoreServices): AstReflection;
|
||||
//# sourceMappingURL=ast-reflection-interpreter.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ast-reflection-interpreter.d.ts","sourceRoot":"","sources":["../../src/grammar/ast-reflection-interpreter.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,aAAa,EAAkC,MAAM,mBAAmB,CAAC;AACvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,uCAAuC,CAAC;AAOhF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAAC;AAC1E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAAC"}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/******************************************************************************
|
||||
* 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 { AbstractAstReflection } from '../syntax-tree.js';
|
||||
import { MultiMap } from '../utils/collections.js';
|
||||
import { isGrammar } from '../languages/generated/ast.js';
|
||||
import { collectAst } from './type-system/ast-collector.js';
|
||||
import { collectTypeHierarchy, findReferenceTypes, isAstType, mergeTypesAndInterfaces } from './type-system/types-util.js';
|
||||
export function interpretAstReflection(grammarOrTypes, services) {
|
||||
let collectedTypes;
|
||||
if (isGrammar(grammarOrTypes)) {
|
||||
collectedTypes = collectAst(grammarOrTypes, { services });
|
||||
}
|
||||
else {
|
||||
collectedTypes = grammarOrTypes;
|
||||
}
|
||||
const allTypes = collectedTypes.interfaces.map(e => e.name).concat(collectedTypes.unions.filter(e => isAstType(e.type)).map(e => e.name));
|
||||
const references = buildReferenceTypes(collectedTypes);
|
||||
const metaData = buildTypeMetaData(collectedTypes);
|
||||
const superTypes = collectTypeHierarchy(mergeTypesAndInterfaces(collectedTypes)).superTypes;
|
||||
return new InterpretedAstReflection({
|
||||
allTypes,
|
||||
references,
|
||||
metaData,
|
||||
superTypes
|
||||
});
|
||||
}
|
||||
class InterpretedAstReflection extends AbstractAstReflection {
|
||||
constructor(options) {
|
||||
// Build the types object required by AbstractAstReflection
|
||||
const types = {};
|
||||
for (const typeName of options.allTypes) {
|
||||
const typeMetaData = options.metaData.get(typeName);
|
||||
if (typeMetaData) {
|
||||
const properties = {};
|
||||
// Convert properties array to object and add reference types
|
||||
if (Array.isArray(typeMetaData.properties)) {
|
||||
for (const prop of typeMetaData.properties) {
|
||||
const referenceKey = `${typeName}:${prop.name}`;
|
||||
const referenceType = options.references.get(referenceKey);
|
||||
properties[prop.name] = {
|
||||
name: prop.name,
|
||||
defaultValue: prop.defaultValue,
|
||||
...(referenceType && { referenceType })
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If properties is already an object, copy it and add reference types
|
||||
for (const [propName, prop] of Object.entries(typeMetaData.properties)) {
|
||||
const referenceKey = `${typeName}:${propName}`;
|
||||
const referenceType = options.references.get(referenceKey);
|
||||
properties[propName] = {
|
||||
...prop,
|
||||
...(referenceType && { referenceType })
|
||||
};
|
||||
}
|
||||
}
|
||||
types[typeName] = {
|
||||
name: typeName,
|
||||
properties,
|
||||
superTypes: Array.from(options.superTypes.get(typeName))
|
||||
};
|
||||
}
|
||||
}
|
||||
super();
|
||||
// Initialize the readonly types field
|
||||
Object.defineProperty(this, 'types', { value: types });
|
||||
}
|
||||
computeIsSubtype(subtype, originalSuperType) {
|
||||
const typeMetaData = this.types[subtype];
|
||||
if (!typeMetaData) {
|
||||
return false;
|
||||
}
|
||||
for (const superType of typeMetaData.superTypes) {
|
||||
if (this.isSubtype(superType, originalSuperType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function buildReferenceTypes(astTypes) {
|
||||
const references = new MultiMap();
|
||||
for (const interfaceType of astTypes.interfaces) {
|
||||
for (const property of interfaceType.properties) {
|
||||
for (const referenceType of findReferenceTypes(property.type)) {
|
||||
references.add(interfaceType.name, [property.name, referenceType]);
|
||||
}
|
||||
}
|
||||
for (const superType of interfaceType.interfaceSuperTypes) {
|
||||
const superTypeReferences = references.get(superType.name);
|
||||
references.addAll(interfaceType.name, superTypeReferences);
|
||||
}
|
||||
}
|
||||
const map = new Map();
|
||||
for (const [type, [property, target]] of references) {
|
||||
map.set(`${type}:${property}`, target);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
function buildTypeMetaData(astTypes) {
|
||||
const map = new Map();
|
||||
for (const interfaceType of astTypes.interfaces) {
|
||||
const props = interfaceType.superProperties;
|
||||
map.set(interfaceType.name, {
|
||||
name: interfaceType.name,
|
||||
properties: buildPropertyMetaData(props),
|
||||
superTypes: [] // Will be populated later from superTypes data
|
||||
});
|
||||
}
|
||||
return map;
|
||||
}
|
||||
function buildPropertyMetaData(props) {
|
||||
const properties = {};
|
||||
const all = props.sort((a, b) => a.name.localeCompare(b.name));
|
||||
for (const property of all) {
|
||||
properties[property.name] = {
|
||||
name: property.name,
|
||||
defaultValue: property.defaultValue
|
||||
};
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
//# sourceMappingURL=ast-reflection-interpreter.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ast-reflection-interpreter.js","sourceRoot":"","sources":["../../src/grammar/ast-reflection-interpreter.ts"],"names":[],"mappings":"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"}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/******************************************************************************
|
||||
* This file was generated by langium-cli 4.2.1.
|
||||
* DO NOT EDIT MANUALLY!
|
||||
******************************************************************************/
|
||||
import type { Grammar } from '../../languages/generated/ast.js';
|
||||
export declare const LangiumGrammarGrammar: () => Grammar;
|
||||
//# sourceMappingURL=grammar.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar.d.ts","sourceRoot":"","sources":["../../../src/grammar/generated/grammar.ts"],"names":[],"mappings":"AAAA;;;gFAGgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAIhE,eAAO,MAAM,qBAAqB,QAAO,OAAgz5D,CAAC"}
|
||||
+8
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar.js","sourceRoot":"","sources":["../../../src/grammar/generated/grammar.ts"],"names":[],"mappings":"AAAA;;;gFAGgF;AAGhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEpE,IAAI,2BAAgD,CAAC;AACrD,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAY,EAAE,CAAC,2BAA2B,IAAI,CAAC,2BAA2B,GAAG,mBAAmB,CAAC,it5DAAit5D,CAAC,CAAC,CAAC"}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/******************************************************************************
|
||||
* This file was generated by langium-cli 4.2.1.
|
||||
* DO NOT EDIT MANUALLY!
|
||||
******************************************************************************/
|
||||
import type { Module } from '../../dependency-injection.js';
|
||||
import type { LangiumSharedCoreServices, LangiumCoreServices, LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices } from '../../services.js';
|
||||
import type { IParserConfig } from '../../parser/parser-config.js';
|
||||
export declare const LangiumGrammarLanguageMetaData: {
|
||||
readonly languageId: "langium";
|
||||
readonly fileExtensions: readonly [".langium"];
|
||||
readonly caseInsensitive: false;
|
||||
readonly mode: "production";
|
||||
};
|
||||
export declare const LangiumGrammarParserConfig: IParserConfig;
|
||||
export declare const LangiumGrammarGeneratedSharedModule: Module<LangiumSharedCoreServices, LangiumGeneratedSharedCoreServices>;
|
||||
export declare const LangiumGrammarGeneratedModule: Module<LangiumCoreServices, LangiumGeneratedCoreServices>;
|
||||
//# sourceMappingURL=module.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/grammar/generated/module.ts"],"names":[],"mappings":"AAAA;;;gFAGgF;AAIhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,4BAA4B,EAAE,kCAAkC,EAAE,MAAM,mBAAmB,CAAC;AAC1J,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE,eAAO,MAAM,8BAA8B;;;;;CAKN,CAAC;AAEtC,eAAO,MAAM,0BAA0B,EAAE,aAExC,CAAC;AAEF,eAAO,MAAM,mCAAmC,EAAE,MAAM,CAAC,yBAAyB,EAAE,kCAAkC,CAErH,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,mBAAmB,EAAE,4BAA4B,CAMnG,CAAC"}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/******************************************************************************
|
||||
* This file was generated by langium-cli 4.2.1.
|
||||
* DO NOT EDIT MANUALLY!
|
||||
******************************************************************************/
|
||||
import { LangiumGrammarAstReflection } from '../../languages/generated/ast.js';
|
||||
import { LangiumGrammarGrammar } from './grammar.js';
|
||||
export const LangiumGrammarLanguageMetaData = {
|
||||
languageId: 'langium',
|
||||
fileExtensions: ['.langium'],
|
||||
caseInsensitive: false,
|
||||
mode: 'production'
|
||||
};
|
||||
export const LangiumGrammarParserConfig = {
|
||||
maxLookahead: 3,
|
||||
};
|
||||
export const LangiumGrammarGeneratedSharedModule = {
|
||||
AstReflection: () => new LangiumGrammarAstReflection()
|
||||
};
|
||||
export const LangiumGrammarGeneratedModule = {
|
||||
Grammar: () => LangiumGrammarGrammar(),
|
||||
LanguageMetaData: () => LangiumGrammarLanguageMetaData,
|
||||
parser: {
|
||||
ParserConfig: () => LangiumGrammarParserConfig
|
||||
}
|
||||
};
|
||||
//# sourceMappingURL=module.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../../src/grammar/generated/module.ts"],"names":[],"mappings":"AAAA;;;gFAGgF;AAGhF,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAI/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC1C,UAAU,EAAE,SAAS;IACrB,cAAc,EAAE,CAAC,UAAU,CAAC;IAC5B,eAAe,EAAE,KAAK;IACtB,IAAI,EAAE,YAAY;CACe,CAAC;AAEtC,MAAM,CAAC,MAAM,0BAA0B,GAAkB;IACrD,YAAY,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,mCAAmC,GAA0E;IACtH,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,2BAA2B,EAAE;CACzD,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAA8D;IACpG,OAAO,EAAE,GAAG,EAAE,CAAC,qBAAqB,EAAE;IACtC,gBAAgB,EAAE,GAAG,EAAE,CAAC,8BAA8B;IACtD,MAAM,EAAE;QACJ,YAAY,EAAE,GAAG,EAAE,CAAC,0BAA0B;KACjD;CACJ,CAAC"}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
* @module langium/grammar
|
||||
*/
|
||||
export * from './generated/grammar.js';
|
||||
export * from './generated/module.js';
|
||||
export * from './lsp/grammar-call-hierarchy.js';
|
||||
export * from './lsp/grammar-code-actions.js';
|
||||
export * from './lsp/grammar-completion-provider.js';
|
||||
export * from './lsp/grammar-definition.js';
|
||||
export * from './lsp/grammar-folding-ranges.js';
|
||||
export * from './lsp/grammar-formatter.js';
|
||||
export * from './lsp/grammar-semantic-tokens.js';
|
||||
export * from './references/grammar-naming.js';
|
||||
export * from './references/grammar-references.js';
|
||||
export * from './references/grammar-scope.js';
|
||||
export * from './validation/types-validator.js';
|
||||
export * from './validation/validation-resources-collector.js';
|
||||
export * from './validation/validator.js';
|
||||
export * from './type-system/index.js';
|
||||
export * from './langium-grammar-module.js';
|
||||
export * from './internal-grammar-util.js';
|
||||
export * from './ast-reflection-interpreter.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grammar/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC"}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
*
|
||||
* @module langium/grammar
|
||||
*/
|
||||
// This file contains Langium grammar language internals.
|
||||
// It is not supposed to be exported with the general `langium` export.
|
||||
// Instead, it is available from `langium/grammar`.
|
||||
export * from './generated/grammar.js';
|
||||
export * from './generated/module.js';
|
||||
export * from './lsp/grammar-call-hierarchy.js';
|
||||
export * from './lsp/grammar-code-actions.js';
|
||||
export * from './lsp/grammar-completion-provider.js';
|
||||
export * from './lsp/grammar-definition.js';
|
||||
export * from './lsp/grammar-folding-ranges.js';
|
||||
export * from './lsp/grammar-formatter.js';
|
||||
export * from './lsp/grammar-semantic-tokens.js';
|
||||
export * from './references/grammar-naming.js';
|
||||
export * from './references/grammar-references.js';
|
||||
export * from './references/grammar-scope.js';
|
||||
export * from './validation/types-validator.js';
|
||||
export * from './validation/validation-resources-collector.js';
|
||||
export * from './validation/validator.js';
|
||||
export * from './type-system/index.js';
|
||||
export * from './langium-grammar-module.js';
|
||||
export * from './internal-grammar-util.js';
|
||||
export * from './ast-reflection-interpreter.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/grammar/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yDAAyD;AACzD,uEAAuE;AACvE,mDAAmD;AAEnD,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iCAAiC,CAAC"}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/******************************************************************************
|
||||
* 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 { URI } from '../utils/uri-utils.js';
|
||||
import type { LangiumDocuments } from '../workspace/documents.js';
|
||||
import * as ast from '../languages/generated/ast.js';
|
||||
import type { LangiumGrammarServices } from './langium-grammar-module.js';
|
||||
import type { IParserConfig } from '../parser/parser-config.js';
|
||||
import type { LanguageMetaData } from '../languages/language-meta-data.js';
|
||||
import type { Module } from '../dependency-injection.js';
|
||||
import type { LangiumServices, LangiumSharedServices } from '../lsp/lsp-services.js';
|
||||
export declare function hasDataTypeReturn(rule: ast.ParserRule): boolean;
|
||||
export declare function isStringGrammarType(type: ast.AbstractType | ast.TypeDefinition): boolean;
|
||||
export declare function getTypeNameWithoutError(type?: ast.AbstractType | ast.Action): string | undefined;
|
||||
export declare function resolveImportUri(imp: ast.GrammarImport): URI | undefined;
|
||||
export declare function resolveImport(documents: LangiumDocuments, imp: ast.GrammarImport): ast.Grammar | undefined;
|
||||
export declare function resolveTransitiveImports(documents: LangiumDocuments, grammar: ast.Grammar): ast.Grammar[];
|
||||
export declare function resolveTransitiveImports(documents: LangiumDocuments, importNode: ast.GrammarImport): ast.Grammar[];
|
||||
export declare function extractAssignments(element: ast.AbstractElement): ast.Assignment[];
|
||||
export declare function isPrimitiveGrammarType(type: string): boolean;
|
||||
/**
|
||||
* Create an instance of the language services for the given grammar. This function is very
|
||||
* useful when the grammar is defined on-the-fly, for example in tests of the Langium framework.
|
||||
*/
|
||||
export declare function createServicesForGrammar<L extends LangiumServices = LangiumServices, S extends LangiumSharedServices = LangiumSharedServices>(config: {
|
||||
grammar: string | ast.Grammar;
|
||||
grammarServices?: LangiumGrammarServices;
|
||||
parserConfig?: IParserConfig;
|
||||
languageMetaData?: LanguageMetaData;
|
||||
module?: Module<L, unknown>;
|
||||
sharedModule?: Module<S, unknown>;
|
||||
}): Promise<L>;
|
||||
//# sourceMappingURL=internal-grammar-util.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"internal-grammar-util.d.ts","sourceRoot":"","sources":["../../src/grammar/internal-grammar-util.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,KAAK,GAAG,MAAM,+BAA+B,CAAC;AAGrD,OAAO,KAAK,EAAE,sBAAsB,EAAC,MAAM,6BAA6B,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAGxD,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAMrF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,GAAG,OAAO,CAG/D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,cAAc,GAAG,OAAO,CAExF;AAmCD,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,SAAS,CAShG;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,aAAa,GAAG,GAAG,GAAG,SAAS,CAUxE;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,gBAAgB,EAAE,GAAG,EAAE,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,OAAO,GAAG,SAAS,CAc1G;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;AAC1G,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAE,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;AA2CnH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,GAAG,CAAC,eAAe,GAAG,GAAG,CAAC,UAAU,EAAE,CAYjF;AAID,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,CAAC,SAAS,qBAAqB,GAAG,qBAAqB,EAAE,MAAM,EAAE;IACzJ,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;IAC9B,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;CACpC,GAAG,OAAO,CAAC,CAAC,CAAC,CAkCb"}
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/******************************************************************************
|
||||
* 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 { URI } from '../utils/uri-utils.js';
|
||||
import * as ast from '../languages/generated/ast.js';
|
||||
import { getDocument } from '../utils/ast-utils.js';
|
||||
import { UriUtils } from '../utils/uri-utils.js';
|
||||
import { createLangiumGrammarServices } from './langium-grammar-module.js';
|
||||
import { inject } from '../dependency-injection.js';
|
||||
import { createDefaultModule, createDefaultSharedModule } from '../lsp/default-lsp-module.js';
|
||||
import { EmptyFileSystem } from '../workspace/file-system-provider.js';
|
||||
import { interpretAstReflection } from './ast-reflection-interpreter.js';
|
||||
import { getTypeName, isDataType } from '../utils/grammar-utils.js';
|
||||
export function hasDataTypeReturn(rule) {
|
||||
const returnType = rule.returnType?.ref;
|
||||
return rule.dataType !== undefined || (ast.isType(returnType) && isDataType(returnType));
|
||||
}
|
||||
export function isStringGrammarType(type) {
|
||||
return isStringTypeInternal(type, new Set());
|
||||
}
|
||||
function isStringTypeInternal(type, visited) {
|
||||
if (visited.has(type)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
visited.add(type);
|
||||
}
|
||||
if (ast.isParserRule(type)) {
|
||||
if (type.dataType) {
|
||||
return type.dataType === 'string';
|
||||
}
|
||||
if (type.returnType?.ref) {
|
||||
return isStringTypeInternal(type.returnType.ref, visited);
|
||||
}
|
||||
}
|
||||
else if (ast.isType(type)) {
|
||||
return isStringTypeInternal(type.type, visited);
|
||||
}
|
||||
else if (ast.isArrayType(type)) {
|
||||
return false;
|
||||
}
|
||||
else if (ast.isReferenceType(type)) {
|
||||
return false;
|
||||
}
|
||||
else if (ast.isUnionType(type)) {
|
||||
return type.types.every(e => isStringTypeInternal(e, visited));
|
||||
}
|
||||
else if (ast.isSimpleType(type)) {
|
||||
if (type.primitiveType === 'string') {
|
||||
return true;
|
||||
}
|
||||
else if (type.stringType) {
|
||||
return true;
|
||||
}
|
||||
else if (type.typeRef?.ref) {
|
||||
return isStringTypeInternal(type.typeRef.ref, visited);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export function getTypeNameWithoutError(type) {
|
||||
if (!type) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return getTypeName(type);
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
export function resolveImportUri(imp) {
|
||||
if (imp.path === undefined || imp.path.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const dirUri = UriUtils.dirname(getDocument(imp).uri);
|
||||
let grammarPath = imp.path;
|
||||
if (!grammarPath.endsWith('.langium')) {
|
||||
grammarPath += '.langium';
|
||||
}
|
||||
return UriUtils.resolvePath(dirUri, grammarPath);
|
||||
}
|
||||
export function resolveImport(documents, imp) {
|
||||
const resolvedUri = resolveImportUri(imp);
|
||||
if (!resolvedUri) {
|
||||
return undefined;
|
||||
}
|
||||
const resolvedDocument = documents.getDocument(resolvedUri);
|
||||
if (!resolvedDocument) {
|
||||
return undefined;
|
||||
}
|
||||
const node = resolvedDocument.parseResult.value;
|
||||
if (ast.isGrammar(node)) {
|
||||
return node;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function resolveTransitiveImports(documents, grammarOrImport) {
|
||||
if (ast.isGrammarImport(grammarOrImport)) {
|
||||
const resolvedGrammar = resolveImport(documents, grammarOrImport);
|
||||
if (resolvedGrammar) {
|
||||
const transitiveGrammars = resolveTransitiveImportsInternal(documents, resolvedGrammar);
|
||||
transitiveGrammars.push(resolvedGrammar);
|
||||
return transitiveGrammars;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
return resolveTransitiveImportsInternal(documents, grammarOrImport);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resolves all transitively imported grammars of the given grammar.
|
||||
* In case of grammars importing each other in circular way, each grammar is remembered only once.
|
||||
* The initial grammar will never be part of the result.
|
||||
* @param documents the service to get all available Langium documents
|
||||
* @param grammar the grammar to transitively resolve its imported grammars
|
||||
* @param initialGrammar Even if the initial grammar transitively imports itself in circular way again, the initial grammar will not be part of the result!
|
||||
* @param visited since grammars might import each other in circular way, this set remembers the already visited gramar URIs to prevent loops
|
||||
* @param grammars the result set of already imported and resolved grammars
|
||||
* @returns the collected `grammars` in a new array
|
||||
*/
|
||||
function resolveTransitiveImportsInternal(documents, grammar, initialGrammar = grammar, visited = new Set(), grammars = new Set()) {
|
||||
const doc = getDocument(grammar);
|
||||
if (initialGrammar !== grammar) {
|
||||
grammars.add(grammar);
|
||||
}
|
||||
if (!visited.has(doc.uri)) {
|
||||
visited.add(doc.uri);
|
||||
for (const imp of grammar.imports) {
|
||||
const importedGrammar = resolveImport(documents, imp);
|
||||
if (importedGrammar) {
|
||||
resolveTransitiveImportsInternal(documents, importedGrammar, initialGrammar, visited, grammars);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(grammars);
|
||||
}
|
||||
export function extractAssignments(element) {
|
||||
if (ast.isAssignment(element)) {
|
||||
return [element];
|
||||
}
|
||||
else if (ast.isAlternatives(element) || ast.isGroup(element) || ast.isUnorderedGroup(element)) {
|
||||
return element.elements.flatMap(e => extractAssignments(e));
|
||||
}
|
||||
else if (ast.isRuleCall(element) && element.rule.ref) {
|
||||
if (ast.isInfixRule(element.rule.ref)) {
|
||||
return [];
|
||||
}
|
||||
return extractAssignments(element.rule.ref.definition);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
const primitiveTypes = ['string', 'number', 'boolean', 'Date', 'bigint'];
|
||||
export function isPrimitiveGrammarType(type) {
|
||||
return primitiveTypes.includes(type);
|
||||
}
|
||||
/**
|
||||
* Create an instance of the language services for the given grammar. This function is very
|
||||
* useful when the grammar is defined on-the-fly, for example in tests of the Langium framework.
|
||||
*/
|
||||
export async function createServicesForGrammar(config) {
|
||||
const grammarServices = config.grammarServices ?? createLangiumGrammarServices(EmptyFileSystem).grammar;
|
||||
const uri = URI.parse('memory:/grammar.langium');
|
||||
const factory = grammarServices.shared.workspace.LangiumDocumentFactory;
|
||||
const grammarDocument = typeof config.grammar === 'string'
|
||||
? factory.fromString(config.grammar, uri)
|
||||
: getDocument(config.grammar);
|
||||
const grammarNode = grammarDocument.parseResult.value;
|
||||
const documentBuilder = grammarServices.shared.workspace.DocumentBuilder;
|
||||
await documentBuilder.build([grammarDocument], { validation: false });
|
||||
const parserConfig = config.parserConfig ?? {
|
||||
skipValidations: false
|
||||
};
|
||||
const languageMetaData = config.languageMetaData ?? {
|
||||
caseInsensitive: false,
|
||||
fileExtensions: ['.txt'],
|
||||
languageId: grammarNode.name ?? 'UNKNOWN',
|
||||
mode: 'development'
|
||||
};
|
||||
const generatedSharedModule = {
|
||||
AstReflection: () => interpretAstReflection(grammarNode),
|
||||
};
|
||||
const generatedModule = {
|
||||
Grammar: () => grammarNode,
|
||||
LanguageMetaData: () => languageMetaData,
|
||||
parser: {
|
||||
ParserConfig: () => parserConfig
|
||||
}
|
||||
};
|
||||
const shared = inject(createDefaultSharedModule(EmptyFileSystem), generatedSharedModule, config.sharedModule);
|
||||
const services = inject(createDefaultModule({ shared }), generatedModule, config.module);
|
||||
shared.ServiceRegistry.register(services);
|
||||
return services;
|
||||
}
|
||||
//# sourceMappingURL=internal-grammar-util.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+34
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************
|
||||
* 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 { Module } from '../dependency-injection.js';
|
||||
import type { DeepPartial } from '../services.js';
|
||||
import type { LangiumServices, LangiumSharedServices, PartialLangiumServices, PartialLangiumSharedServices } from '../lsp/lsp-services.js';
|
||||
import { type DefaultSharedModuleContext } from '../lsp/default-lsp-module.js';
|
||||
import { LangiumGrammarValidator } from './validation/validator.js';
|
||||
import { LangiumGrammarValidationResourcesCollector } from './validation/validation-resources-collector.js';
|
||||
import { LangiumGrammarTypesValidator } from './validation/types-validator.js';
|
||||
export type LangiumGrammarAddedServices = {
|
||||
validation: {
|
||||
LangiumGrammarValidator: LangiumGrammarValidator;
|
||||
ValidationResourcesCollector: LangiumGrammarValidationResourcesCollector;
|
||||
LangiumGrammarTypesValidator: LangiumGrammarTypesValidator;
|
||||
};
|
||||
};
|
||||
export type LangiumGrammarServices = LangiumServices & LangiumGrammarAddedServices;
|
||||
export declare const LangiumGrammarModule: Module<LangiumGrammarServices, PartialLangiumServices & LangiumGrammarAddedServices>;
|
||||
/**
|
||||
* Creates Langium grammar services, enriched with LSP functionality
|
||||
*
|
||||
* @param context Shared module context, used to create additional shared modules
|
||||
* @param sharedModule Existing shared module to inject together with new shared services
|
||||
* @param module Additional/modified service implementations for the language services
|
||||
* @returns Shared services enriched with LSP services + Grammar services, per usual
|
||||
*/
|
||||
export declare function createLangiumGrammarServices(context: DefaultSharedModuleContext, sharedModule?: Module<LangiumSharedServices, PartialLangiumSharedServices>, module?: Module<LangiumGrammarServices, DeepPartial<LangiumServices & LangiumGrammarAddedServices>>): {
|
||||
shared: LangiumSharedServices;
|
||||
grammar: LangiumGrammarServices;
|
||||
};
|
||||
//# sourceMappingURL=langium-grammar-module.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"langium-grammar-module.d.ts","sourceRoot":"","sources":["../../src/grammar/langium-grammar-module.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAI3I,OAAO,EAAE,KAAK,0BAA0B,EAAkD,MAAM,8BAA8B,CAAC;AAI/H,OAAO,EAAE,uBAAuB,EAA4B,MAAM,2BAA2B,CAAC;AAU9F,OAAO,EAAE,0CAA0C,EAAE,MAAM,gDAAgD,CAAC;AAC5G,OAAO,EAAE,4BAA4B,EAAgC,MAAM,iCAAiC,CAAC;AAG7G,MAAM,MAAM,2BAA2B,GAAG;IACtC,UAAU,EAAE;QACR,uBAAuB,EAAE,uBAAuB,CAAC;QACjD,4BAA4B,EAAE,0CAA0C,CAAC;QACzE,4BAA4B,EAAE,4BAA4B,CAAC;KAC9D,CAAA;CACJ,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG,2BAA2B,CAAC;AAEnF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,sBAAsB,EAAE,sBAAsB,GAAG,2BAA2B,CAsBrH,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,0BAA0B,EAC5E,YAAY,CAAC,EAAE,MAAM,CAAC,qBAAqB,EAAE,4BAA4B,CAAC,EAC1E,MAAM,CAAC,EAAE,MAAM,CAAC,sBAAsB,EAAE,WAAW,CAAC,eAAe,GAAG,2BAA2B,CAAC,CAAC,GAAG;IACtG,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,EAAE,sBAAsB,CAAA;CAClC,CAyBA"}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/******************************************************************************
|
||||
* 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 { LangiumGrammarTypeHierarchyProvider } from './lsp/grammar-type-hierarchy.js';
|
||||
import { createDefaultModule, createDefaultSharedModule } from '../lsp/default-lsp-module.js';
|
||||
import { inject } from '../dependency-injection.js';
|
||||
import { LangiumGrammarGeneratedModule, LangiumGrammarGeneratedSharedModule } from './generated/module.js';
|
||||
import { LangiumGrammarScopeComputation, LangiumGrammarScopeProvider } from './references/grammar-scope.js';
|
||||
import { LangiumGrammarValidator, registerValidationChecks } from './validation/validator.js';
|
||||
import { LangiumGrammarCodeActionProvider } from './lsp/grammar-code-actions.js';
|
||||
import { LangiumGrammarCompletionProvider } from './lsp/grammar-completion-provider.js';
|
||||
import { LangiumGrammarFoldingRangeProvider } from './lsp/grammar-folding-ranges.js';
|
||||
import { LangiumGrammarFormatter } from './lsp/grammar-formatter.js';
|
||||
import { LangiumGrammarSemanticTokenProvider } from './lsp/grammar-semantic-tokens.js';
|
||||
import { LangiumGrammarNameProvider } from './references/grammar-naming.js';
|
||||
import { LangiumGrammarReferences } from './references/grammar-references.js';
|
||||
import { LangiumGrammarDefinitionProvider } from './lsp/grammar-definition.js';
|
||||
import { LangiumGrammarCallHierarchyProvider } from './lsp/grammar-call-hierarchy.js';
|
||||
import { LangiumGrammarValidationResourcesCollector } from './validation/validation-resources-collector.js';
|
||||
import { LangiumGrammarTypesValidator, registerTypeValidationChecks } from './validation/types-validator.js';
|
||||
import { DocumentState } from '../workspace/documents.js';
|
||||
export const LangiumGrammarModule = {
|
||||
validation: {
|
||||
LangiumGrammarValidator: (services) => new LangiumGrammarValidator(services),
|
||||
ValidationResourcesCollector: (services) => new LangiumGrammarValidationResourcesCollector(services),
|
||||
LangiumGrammarTypesValidator: () => new LangiumGrammarTypesValidator(),
|
||||
},
|
||||
lsp: {
|
||||
FoldingRangeProvider: (services) => new LangiumGrammarFoldingRangeProvider(services),
|
||||
CodeActionProvider: (services) => new LangiumGrammarCodeActionProvider(services),
|
||||
SemanticTokenProvider: (services) => new LangiumGrammarSemanticTokenProvider(services),
|
||||
Formatter: () => new LangiumGrammarFormatter(),
|
||||
DefinitionProvider: (services) => new LangiumGrammarDefinitionProvider(services),
|
||||
CallHierarchyProvider: (services) => new LangiumGrammarCallHierarchyProvider(services),
|
||||
TypeHierarchyProvider: (services) => new LangiumGrammarTypeHierarchyProvider(services),
|
||||
CompletionProvider: (services) => new LangiumGrammarCompletionProvider(services)
|
||||
},
|
||||
references: {
|
||||
ScopeComputation: (services) => new LangiumGrammarScopeComputation(services),
|
||||
ScopeProvider: (services) => new LangiumGrammarScopeProvider(services),
|
||||
References: (services) => new LangiumGrammarReferences(services),
|
||||
NameProvider: () => new LangiumGrammarNameProvider()
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Creates Langium grammar services, enriched with LSP functionality
|
||||
*
|
||||
* @param context Shared module context, used to create additional shared modules
|
||||
* @param sharedModule Existing shared module to inject together with new shared services
|
||||
* @param module Additional/modified service implementations for the language services
|
||||
* @returns Shared services enriched with LSP services + Grammar services, per usual
|
||||
*/
|
||||
export function createLangiumGrammarServices(context, sharedModule, module) {
|
||||
const shared = inject(createDefaultSharedModule(context), LangiumGrammarGeneratedSharedModule, sharedModule);
|
||||
const grammar = inject(createDefaultModule({ shared }), LangiumGrammarGeneratedModule, LangiumGrammarModule, module);
|
||||
addTypeCollectionPhase(shared, grammar);
|
||||
shared.ServiceRegistry.register(grammar);
|
||||
registerValidationChecks(grammar);
|
||||
registerTypeValidationChecks(grammar);
|
||||
if (!context.connection) {
|
||||
// We don't run inside a language server
|
||||
// Therefore, initialize the configuration provider instantly
|
||||
shared.workspace.ConfigurationProvider.initialized({});
|
||||
}
|
||||
return { shared, grammar };
|
||||
}
|
||||
function addTypeCollectionPhase(sharedServices, grammarServices) {
|
||||
const documentBuilder = sharedServices.workspace.DocumentBuilder;
|
||||
documentBuilder.onDocumentPhase(DocumentState.IndexedReferences, async (document) => {
|
||||
const typeCollector = grammarServices.validation.ValidationResourcesCollector;
|
||||
const grammar = document.parseResult.value;
|
||||
document.validationResources = typeCollector.collectValidationResources(grammar);
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=langium-grammar-module.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"langium-grammar-module.js","sourceRoot":"","sources":["../../src/grammar/langium-grammar-module.ts"],"names":[],"mappings":"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"}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/******************************************************************************
|
||||
* 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 { CallHierarchyIncomingCall, CallHierarchyOutgoingCall } from 'vscode-languageserver';
|
||||
import type { AstNode } from '../../syntax-tree.js';
|
||||
import type { Stream } from '../../utils/stream.js';
|
||||
import type { ReferenceDescription } from '../../workspace/ast-descriptions.js';
|
||||
import { AbstractCallHierarchyProvider } from '../../lsp/call-hierarchy-provider.js';
|
||||
export declare class LangiumGrammarCallHierarchyProvider extends AbstractCallHierarchyProvider {
|
||||
protected getIncomingCalls(node: AstNode, references: Stream<ReferenceDescription>): CallHierarchyIncomingCall[] | undefined;
|
||||
protected getOutgoingCalls(node: AstNode): CallHierarchyOutgoingCall[] | undefined;
|
||||
}
|
||||
//# sourceMappingURL=grammar-call-hierarchy.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-call-hierarchy.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-call-hierarchy.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,yBAAyB,EAAE,yBAAyB,EAAS,MAAM,uBAAuB,CAAC;AACzG,OAAO,KAAK,EAAE,OAAO,EAAW,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAEhF,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AAKrF,qBAAa,mCAAoC,SAAQ,6BAA6B;IAElF,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,oBAAoB,CAAC,GAAG,yBAAyB,EAAE,GAAG,SAAS;IAiD5H,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,yBAAyB,EAAE,GAAG,SAAS;CAmErF"}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/******************************************************************************
|
||||
* 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 { SymbolKind } from 'vscode-languageserver';
|
||||
import { AbstractCallHierarchyProvider } from '../../lsp/call-hierarchy-provider.js';
|
||||
import { getContainerOfType, getDocument, streamAllContents } from '../../utils/ast-utils.js';
|
||||
import { findLeafNodeAtOffset } from '../../utils/cst-utils.js';
|
||||
import { isAbstractParserRule, isInfixRule, isParserRule, isRuleCall } from '../../languages/generated/ast.js';
|
||||
export class LangiumGrammarCallHierarchyProvider extends AbstractCallHierarchyProvider {
|
||||
getIncomingCalls(node, references) {
|
||||
if (!isAbstractParserRule(node)) {
|
||||
return undefined;
|
||||
}
|
||||
// This map is used to group incoming calls to avoid duplicates.
|
||||
const uniqueRules = new Map();
|
||||
references.forEach(ref => {
|
||||
const doc = this.documents.getDocument(ref.sourceUri);
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
const rootNode = doc.parseResult.value;
|
||||
if (!rootNode.$cstNode) {
|
||||
return;
|
||||
}
|
||||
const targetNode = findLeafNodeAtOffset(rootNode.$cstNode, ref.segment.offset);
|
||||
if (!targetNode) {
|
||||
return;
|
||||
}
|
||||
const parserRule = getContainerOfType(targetNode.astNode, isAbstractParserRule);
|
||||
if (!parserRule || !parserRule.$cstNode) {
|
||||
return;
|
||||
}
|
||||
const nameNode = this.nameProvider.getNameNode(parserRule);
|
||||
if (!nameNode) {
|
||||
return;
|
||||
}
|
||||
const refDocUri = ref.sourceUri.toString();
|
||||
const ruleId = refDocUri + '@' + nameNode.text;
|
||||
uniqueRules.has(ruleId) ?
|
||||
uniqueRules.set(ruleId, { parserRule: parserRule.$cstNode, nameNode, targetNodes: [...uniqueRules.get(ruleId).targetNodes, targetNode], docUri: refDocUri })
|
||||
: uniqueRules.set(ruleId, { parserRule: parserRule.$cstNode, nameNode, targetNodes: [targetNode], docUri: refDocUri });
|
||||
});
|
||||
if (uniqueRules.size === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return Array.from(uniqueRules.values()).map(rule => ({
|
||||
from: {
|
||||
kind: SymbolKind.Method,
|
||||
name: rule.nameNode.text,
|
||||
range: rule.parserRule.range,
|
||||
selectionRange: rule.nameNode.range,
|
||||
uri: rule.docUri
|
||||
},
|
||||
fromRanges: rule.targetNodes.map(node => node.range)
|
||||
}));
|
||||
}
|
||||
getOutgoingCalls(node) {
|
||||
if (isParserRule(node)) {
|
||||
const ruleCalls = streamAllContents(node).filter(isRuleCall).toArray();
|
||||
// This map is used to group outgoing calls to avoid duplicates.
|
||||
const uniqueRules = new Map();
|
||||
ruleCalls.forEach(ruleCall => {
|
||||
const cstNode = ruleCall.$cstNode;
|
||||
if (!cstNode) {
|
||||
return;
|
||||
}
|
||||
const refCstNode = ruleCall.rule.ref?.$cstNode;
|
||||
if (!refCstNode) {
|
||||
return;
|
||||
}
|
||||
const refNameNode = this.nameProvider.getNameNode(refCstNode.astNode);
|
||||
if (!refNameNode) {
|
||||
return;
|
||||
}
|
||||
const refDocUri = getDocument(refCstNode.astNode).uri.toString();
|
||||
const ruleId = refDocUri + '@' + refNameNode.text;
|
||||
uniqueRules.has(ruleId) ?
|
||||
uniqueRules.set(ruleId, { refCstNode: refCstNode, to: refNameNode, from: [...uniqueRules.get(ruleId).from, cstNode.range], docUri: refDocUri })
|
||||
: uniqueRules.set(ruleId, { refCstNode: refCstNode, to: refNameNode, from: [cstNode.range], docUri: refDocUri });
|
||||
});
|
||||
if (uniqueRules.size === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return Array.from(uniqueRules.values()).map(rule => ({
|
||||
to: {
|
||||
kind: SymbolKind.Method,
|
||||
name: rule.to.text,
|
||||
range: rule.refCstNode.range,
|
||||
selectionRange: rule.to.range,
|
||||
uri: rule.docUri
|
||||
},
|
||||
fromRanges: rule.from
|
||||
}));
|
||||
}
|
||||
else if (isInfixRule(node)) {
|
||||
const ruleCall = node.call;
|
||||
const cstNode = ruleCall.$cstNode;
|
||||
if (!cstNode) {
|
||||
return undefined;
|
||||
}
|
||||
const refCstNode = ruleCall.rule.ref?.$cstNode;
|
||||
if (!refCstNode) {
|
||||
return undefined;
|
||||
}
|
||||
const refNameNode = this.nameProvider.getNameNode(refCstNode.astNode);
|
||||
if (!refNameNode) {
|
||||
return undefined;
|
||||
}
|
||||
const refDocUri = getDocument(refCstNode.astNode).uri.toString();
|
||||
return [{
|
||||
to: {
|
||||
kind: SymbolKind.Method,
|
||||
name: refNameNode.text,
|
||||
range: refCstNode.range,
|
||||
selectionRange: refNameNode.range,
|
||||
uri: refDocUri
|
||||
},
|
||||
fromRanges: [cstNode.range]
|
||||
}];
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-call-hierarchy.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-call-hierarchy.js","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-call-hierarchy.ts"],"names":[],"mappings":"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"}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/******************************************************************************
|
||||
* 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 { CodeActionParams } from 'vscode-languageserver-protocol';
|
||||
import type { CodeAction, Command } from 'vscode-languageserver-types';
|
||||
import * as ast from '../../languages/generated/ast.js';
|
||||
import type { CodeActionProvider } from '../../lsp/code-action.js';
|
||||
import type { LangiumServices } from '../../lsp/lsp-services.js';
|
||||
import type { AstReflection } from '../../syntax-tree.js';
|
||||
import type { MaybePromise } from '../../utils/promise-utils.js';
|
||||
import type { LangiumDocument } from '../../workspace/documents.js';
|
||||
import type { IndexManager } from '../../workspace/index-manager.js';
|
||||
export declare class LangiumGrammarCodeActionProvider implements CodeActionProvider {
|
||||
protected readonly reflection: AstReflection;
|
||||
protected readonly indexManager: IndexManager;
|
||||
constructor(services: LangiumServices);
|
||||
getCodeActions(document: LangiumDocument<ast.Grammar>, params: CodeActionParams): MaybePromise<Array<Command | CodeAction>>;
|
||||
private createCodeActions;
|
||||
/**
|
||||
* Adds missing returns for parser rule
|
||||
*/
|
||||
private fixMissingReturns;
|
||||
private fixInvalidReturnsInfers;
|
||||
private fixMissingInfer;
|
||||
private fixMissingCrossRefTerminal;
|
||||
private fixSuperfluousInfer;
|
||||
private isRuleReplaceable;
|
||||
private replaceRule;
|
||||
private isDefinitionReplaceable;
|
||||
private replaceDefinition;
|
||||
private replaceParserRuleByTypeDeclaration;
|
||||
private fixUnnecessaryFileExtension;
|
||||
private makeUpperCase;
|
||||
private addEntryKeyword;
|
||||
private fixRegexTokens;
|
||||
private fixCrossRefSyntax;
|
||||
private addNewRule;
|
||||
private lookInGlobalScope;
|
||||
}
|
||||
//# sourceMappingURL=grammar-code-actions.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-code-actions.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-code-actions.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAY,MAAM,6BAA6B,CAAC;AACjF,OAAO,KAAK,GAAG,MAAM,kCAAkC,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAA4B,MAAM,sBAAsB,CAAC;AAGpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAGrE,qBAAa,gCAAiC,YAAW,kBAAkB;IAEvE,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;gBAElC,QAAQ,EAAE,eAAe;IAKrC,cAAc,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,gBAAgB,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,CAAC;IAS3H,OAAO,CAAC,iBAAiB;IAmDzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,uBAAuB;IAqB/B,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,0BAA0B;IAwBlC,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,kCAAkC;IA8B1C,OAAO,CAAC,2BAA2B;IAwBnC,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,cAAc;IA4BtB,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,iBAAiB;CA0E5B"}
|
||||
+458
@@ -0,0 +1,458 @@
|
||||
/******************************************************************************
|
||||
* 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 { CodeActionKind } from 'vscode-languageserver';
|
||||
import * as ast from '../../languages/generated/ast.js';
|
||||
import { getContainerOfType } from '../../utils/ast-utils.js';
|
||||
import { findLeafNodeAtOffset } from '../../utils/cst-utils.js';
|
||||
import { escapeRegExp } from '../../utils/regexp-utils.js';
|
||||
import { UriUtils } from '../../utils/uri-utils.js';
|
||||
import { DocumentValidator } from '../../validation/document-validator.js';
|
||||
import { IssueCodes } from '../validation/validator.js';
|
||||
export class LangiumGrammarCodeActionProvider {
|
||||
constructor(services) {
|
||||
this.reflection = services.shared.AstReflection;
|
||||
this.indexManager = services.shared.workspace.IndexManager;
|
||||
}
|
||||
getCodeActions(document, params) {
|
||||
const result = [];
|
||||
const acceptor = (ca) => ca && result.push(ca);
|
||||
for (const diagnostic of params.context.diagnostics) {
|
||||
this.createCodeActions(diagnostic, document, acceptor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
createCodeActions(diagnostic, document, accept) {
|
||||
switch (diagnostic.data?.code) {
|
||||
case IssueCodes.GrammarNameUppercase:
|
||||
case IssueCodes.RuleNameUppercase:
|
||||
accept(this.makeUpperCase(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.UseRegexTokens:
|
||||
accept(this.fixRegexTokens(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.EntryRuleTokenSyntax:
|
||||
accept(this.addEntryKeyword(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.CrossRefTokenSyntax:
|
||||
accept(this.fixCrossRefSyntax(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.ParserRuleToTypeDecl:
|
||||
accept(this.replaceParserRuleByTypeDeclaration(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.UnnecessaryFileExtension:
|
||||
accept(this.fixUnnecessaryFileExtension(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.MissingReturns:
|
||||
accept(this.fixMissingReturns(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.InvalidInfers:
|
||||
case IssueCodes.InvalidReturns:
|
||||
accept(this.fixInvalidReturnsInfers(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.MissingInfer:
|
||||
accept(this.fixMissingInfer(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.MissingCrossRefTerminal:
|
||||
accept(this.fixMissingCrossRefTerminal(diagnostic, document));
|
||||
break;
|
||||
case IssueCodes.SuperfluousInfer:
|
||||
accept(this.fixSuperfluousInfer(diagnostic, document));
|
||||
break;
|
||||
case DocumentValidator.LinkingError: {
|
||||
const data = diagnostic.data;
|
||||
if (data && data.containerType === 'RuleCall' && data.property === 'rule') {
|
||||
accept(this.addNewRule(diagnostic, data, document));
|
||||
}
|
||||
if (data) {
|
||||
this.lookInGlobalScope(diagnostic, data, document).forEach(accept);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Adds missing returns for parser rule
|
||||
*/
|
||||
fixMissingReturns(diagnostic, document) {
|
||||
const text = document.textDocument.getText(diagnostic.range);
|
||||
if (text) {
|
||||
return {
|
||||
title: `Add explicit return type for parser rule ${text}`,
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: diagnostic.range,
|
||||
newText: `${text} returns ${text}` // suggestion adds missing 'return'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
fixInvalidReturnsInfers(diagnostic, document) {
|
||||
const data = diagnostic.data;
|
||||
if (data && data.actionSegment) {
|
||||
const text = document.textDocument.getText(data.actionSegment.range);
|
||||
return {
|
||||
title: `Correct ${text} usage`,
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: data.actionSegment.range,
|
||||
newText: text === 'infers' ? 'returns' : 'infers'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
fixMissingInfer(diagnostic, document) {
|
||||
const data = diagnostic.data;
|
||||
if (data && data.actionSegment) {
|
||||
return {
|
||||
title: "Correct 'infer' usage",
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: {
|
||||
start: data.actionSegment.range.end,
|
||||
end: data.actionSegment.range.end
|
||||
},
|
||||
newText: 'infer '
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
fixMissingCrossRefTerminal(diagnostic, document) {
|
||||
const grammar = document.parseResult.value;
|
||||
const idTerminal = grammar.rules.find(rule => ast.isTerminalRule(rule) && rule.name === 'ID');
|
||||
if (idTerminal) {
|
||||
return {
|
||||
title: 'Use ID token to resolve cross-reference',
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: {
|
||||
start: diagnostic.range.end,
|
||||
end: diagnostic.range.end
|
||||
},
|
||||
newText: ':ID'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
fixSuperfluousInfer(diagnostic, document) {
|
||||
const data = diagnostic.data;
|
||||
if (data && data.actionRange) {
|
||||
return {
|
||||
title: "Remove the 'infer' keyword",
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: data.actionRange,
|
||||
newText: ''
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
isRuleReplaceable(rule) {
|
||||
/** at the moment, only "pure" parser rules are supported:
|
||||
* - supported are only Alternatives (recursively) and "infers"
|
||||
* - "returns" is not relevant, since cross-references would not refer to the parser rule, but to its "return type" instead
|
||||
*/
|
||||
return !rule.fragment && !rule.entry && rule.parameters.length === 0 && !rule.returnType && !rule.dataType;
|
||||
}
|
||||
replaceRule(rule) {
|
||||
const type = rule.inferredType ?? rule;
|
||||
return type.name;
|
||||
}
|
||||
isDefinitionReplaceable(node) {
|
||||
if (ast.isRuleCall(node)) {
|
||||
return node.arguments.length === 0 && ast.isParserRule(node.rule.ref) && this.isRuleReplaceable(node.rule.ref);
|
||||
}
|
||||
if (ast.isAlternatives(node)) {
|
||||
return node.elements.every(child => this.isDefinitionReplaceable(child));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
replaceDefinition(node) {
|
||||
if (ast.isRuleCall(node) && node.rule.ref) {
|
||||
return node.rule.ref.name;
|
||||
}
|
||||
if (ast.isAlternatives(node)) {
|
||||
return node.elements.map(child => this.replaceDefinition(child)).join(' | ');
|
||||
}
|
||||
throw new Error('missing code for ' + node);
|
||||
}
|
||||
replaceParserRuleByTypeDeclaration(diagnostic, document) {
|
||||
const rootCst = document.parseResult.value.$cstNode;
|
||||
if (rootCst) {
|
||||
const offset = document.textDocument.offsetAt(diagnostic.range.start);
|
||||
const cstNode = findLeafNodeAtOffset(rootCst, offset);
|
||||
const rule = getContainerOfType(cstNode?.astNode, ast.isParserRule);
|
||||
if (rule && rule.$cstNode) {
|
||||
const isReplaceable = this.isRuleReplaceable(rule) && this.isDefinitionReplaceable(rule.definition);
|
||||
if (isReplaceable) {
|
||||
const newText = `type ${this.replaceRule(rule)} = ${this.replaceDefinition(rule.definition)};`;
|
||||
return {
|
||||
title: 'Replace with type declaration',
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: true,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: diagnostic.range,
|
||||
newText
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
fixUnnecessaryFileExtension(diagnostic, document) {
|
||||
const end = { ...diagnostic.range.end };
|
||||
end.character -= 1;
|
||||
const start = { ...end };
|
||||
start.character -= '.langium'.length;
|
||||
return {
|
||||
title: 'Remove file extension',
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: true,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: {
|
||||
start,
|
||||
end
|
||||
},
|
||||
newText: ''
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
makeUpperCase(diagnostic, document) {
|
||||
const range = {
|
||||
start: diagnostic.range.start,
|
||||
end: {
|
||||
line: diagnostic.range.start.line,
|
||||
character: diagnostic.range.start.character + 1
|
||||
}
|
||||
};
|
||||
return {
|
||||
title: 'First letter to upper case',
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: true,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range,
|
||||
newText: document.textDocument.getText(range).toUpperCase()
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
addEntryKeyword(diagnostic, document) {
|
||||
return {
|
||||
title: 'Add entry keyword',
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: true,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: { start: diagnostic.range.start, end: diagnostic.range.start },
|
||||
newText: 'entry '
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
fixRegexTokens(diagnostic, document) {
|
||||
const offset = document.textDocument.offsetAt(diagnostic.range.start);
|
||||
const rootCst = document.parseResult.value.$cstNode;
|
||||
if (rootCst) {
|
||||
const cstNode = findLeafNodeAtOffset(rootCst, offset);
|
||||
const container = getContainerOfType(cstNode?.astNode, ast.isCharacterRange);
|
||||
if (container && container.right && container.$cstNode) {
|
||||
const left = container.left.value;
|
||||
const right = container.right.value;
|
||||
return {
|
||||
title: 'Refactor into regular expression',
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: true,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: container.$cstNode.range,
|
||||
newText: `/[${escapeRegExp(left)}-${escapeRegExp(right)}]/`
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
fixCrossRefSyntax(diagnostic, document) {
|
||||
return {
|
||||
title: "Replace '|' with ':'",
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: true,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: diagnostic.range,
|
||||
newText: ':'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
addNewRule(diagnostic, data, document) {
|
||||
const offset = document.textDocument.offsetAt(diagnostic.range.start);
|
||||
const rootCst = document.parseResult.value.$cstNode;
|
||||
if (rootCst) {
|
||||
const cstNode = findLeafNodeAtOffset(rootCst, offset);
|
||||
const container = getContainerOfType(cstNode?.astNode, ast.isParserRule);
|
||||
if (container && container.$cstNode) {
|
||||
return {
|
||||
title: `Add new rule '${data.refText}'`,
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: false,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: {
|
||||
start: container.$cstNode.range.end,
|
||||
end: container.$cstNode.range.end
|
||||
},
|
||||
newText: '\n\n' + data.refText + ':\n /* TODO implement rule */ {infer ' + data.refText + '};'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
lookInGlobalScope(diagnostic, data, document) {
|
||||
const refInfo = {
|
||||
container: {
|
||||
$type: data.containerType
|
||||
},
|
||||
property: data.property,
|
||||
reference: {
|
||||
$refText: data.refText
|
||||
}
|
||||
};
|
||||
const referenceType = this.reflection.getReferenceType(refInfo);
|
||||
const candidates = this.indexManager.allElements(referenceType).filter(e => e.name === data.refText);
|
||||
const result = [];
|
||||
let shortestPathIndex = -1;
|
||||
let shortestPathLength = -1;
|
||||
for (const candidate of candidates) {
|
||||
if (UriUtils.equals(candidate.documentUri, document.uri)) {
|
||||
continue;
|
||||
}
|
||||
// Find an import path and a position to insert the import
|
||||
const importPath = getRelativeImport(document.uri, candidate.documentUri);
|
||||
let position;
|
||||
let suffix = '';
|
||||
const grammar = document.parseResult.value;
|
||||
const nextImport = grammar.imports.find(imp => imp.path && importPath < imp.path);
|
||||
if (nextImport) {
|
||||
// Insert the new import alphabetically
|
||||
position = nextImport.$cstNode?.range.start;
|
||||
}
|
||||
else if (grammar.imports.length > 0) {
|
||||
// Put the new import after the last import
|
||||
const rangeEnd = grammar.imports[grammar.imports.length - 1].$cstNode.range.end;
|
||||
if (rangeEnd) {
|
||||
position = { line: rangeEnd.line + 1, character: 0 };
|
||||
}
|
||||
}
|
||||
else if (grammar.rules.length > 0) {
|
||||
// Put the new import before the first rule
|
||||
position = grammar.rules[0].$cstNode?.range.start;
|
||||
suffix = '\n';
|
||||
}
|
||||
if (position) {
|
||||
if (shortestPathIndex < 0 || importPath.length < shortestPathLength) {
|
||||
shortestPathIndex = result.length;
|
||||
shortestPathLength = importPath.length;
|
||||
}
|
||||
// Add an import declaration for the candidate in the global scope
|
||||
result.push({
|
||||
title: `Add import to '${importPath}'`,
|
||||
kind: CodeActionKind.QuickFix,
|
||||
diagnostics: [diagnostic],
|
||||
isPreferred: false,
|
||||
edit: {
|
||||
changes: {
|
||||
[document.textDocument.uri]: [{
|
||||
range: {
|
||||
start: position,
|
||||
end: position
|
||||
},
|
||||
newText: `import '${importPath}'\n${suffix}`
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Mark the code action with the shortest import path as preferred
|
||||
if (shortestPathIndex >= 0) {
|
||||
result[shortestPathIndex].isPreferred = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
function getRelativeImport(source, target) {
|
||||
const sourceDir = UriUtils.dirname(source);
|
||||
let relativePath = UriUtils.relative(sourceDir, target);
|
||||
if (!relativePath.startsWith('./') && !relativePath.startsWith('../')) {
|
||||
relativePath = './' + relativePath;
|
||||
}
|
||||
if (relativePath.endsWith('.langium')) {
|
||||
relativePath = relativePath.substring(0, relativePath.length - '.langium'.length);
|
||||
}
|
||||
return relativePath;
|
||||
}
|
||||
//# sourceMappingURL=grammar-code-actions.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
/******************************************************************************
|
||||
* 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 { NextFeature } from '../../lsp/completion/follow-element-computation.js';
|
||||
import { DefaultCompletionProvider, type CompletionAcceptor, type CompletionContext } from '../../lsp/completion/completion-provider.js';
|
||||
import type { MaybePromise } from '../../utils/promise-utils.js';
|
||||
import type { AbstractElement } from '../../languages/generated/ast.js';
|
||||
import type { LangiumServices } from '../../lsp/lsp-services.js';
|
||||
export declare class LangiumGrammarCompletionProvider extends DefaultCompletionProvider {
|
||||
private readonly documents;
|
||||
constructor(services: LangiumServices);
|
||||
protected completionFor(context: CompletionContext, next: NextFeature<AbstractElement>, acceptor: CompletionAcceptor): MaybePromise<void>;
|
||||
private completeImportPath;
|
||||
private getAllFiles;
|
||||
}
|
||||
//# sourceMappingURL=grammar-completion-provider.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-completion-provider.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-completion-provider.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oDAAoD,CAAC;AACtF,OAAO,EAAE,yBAAyB,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AACzI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAGjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,qBAAa,gCAAiC,SAAQ,yBAAyB;IAE3E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;gBAEvC,QAAQ,EAAE,eAAe;cAKlB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,WAAW,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,kBAAkB,GAAG,YAAY,CAAC,IAAI,CAAC;IASlJ,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,WAAW;CAmBtB"}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/******************************************************************************
|
||||
* 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 { CompletionItemKind } from 'vscode-languageserver-types';
|
||||
import { DefaultCompletionProvider } from '../../lsp/completion/completion-provider.js';
|
||||
import { getContainerOfType } from '../../utils/ast-utils.js';
|
||||
import { isAssignment } from '../../languages/generated/ast.js';
|
||||
import { UriUtils } from '../../utils/uri-utils.js';
|
||||
export class LangiumGrammarCompletionProvider extends DefaultCompletionProvider {
|
||||
constructor(services) {
|
||||
super(services);
|
||||
this.documents = () => services.shared.workspace.LangiumDocuments;
|
||||
}
|
||||
completionFor(context, next, acceptor) {
|
||||
const assignment = getContainerOfType(next.feature, isAssignment);
|
||||
if (assignment?.feature === 'path') {
|
||||
this.completeImportPath(context, acceptor);
|
||||
}
|
||||
else {
|
||||
return super.completionFor(context, next, acceptor);
|
||||
}
|
||||
}
|
||||
completeImportPath(context, acceptor) {
|
||||
const text = context.textDocument.getText();
|
||||
const existingText = text.substring(context.tokenOffset, context.offset);
|
||||
let allPaths = this.getAllFiles(context.document);
|
||||
let range = {
|
||||
start: context.position,
|
||||
end: context.position
|
||||
};
|
||||
if (existingText.length > 0) {
|
||||
const existingPath = existingText.substring(1);
|
||||
allPaths = allPaths.filter(path => path.startsWith(existingPath));
|
||||
// Completely replace the current token
|
||||
const start = context.textDocument.positionAt(context.tokenOffset + 1);
|
||||
const end = context.textDocument.positionAt(context.tokenEndOffset - 1);
|
||||
range = {
|
||||
start,
|
||||
end
|
||||
};
|
||||
}
|
||||
for (const path of allPaths) {
|
||||
// Only insert quotes if there is no `path` token yet.
|
||||
const delimiter = existingText.length > 0 ? '' : '"';
|
||||
const completionValue = `${delimiter}${path}${delimiter}`;
|
||||
acceptor(context, {
|
||||
label: path,
|
||||
textEdit: {
|
||||
newText: completionValue,
|
||||
range
|
||||
},
|
||||
kind: CompletionItemKind.File,
|
||||
sortText: '0'
|
||||
});
|
||||
}
|
||||
}
|
||||
getAllFiles(document) {
|
||||
const documents = this.documents().all;
|
||||
const uri = document.uri.toString();
|
||||
const dirname = UriUtils.dirname(document.uri).toString();
|
||||
const paths = [];
|
||||
for (const doc of documents) {
|
||||
if (!UriUtils.equals(doc.uri, uri)) {
|
||||
const docUri = doc.uri.toString();
|
||||
const uriWithoutExt = docUri.substring(0, docUri.length - UriUtils.extname(doc.uri).length);
|
||||
let relativePath = UriUtils.relative(dirname, uriWithoutExt);
|
||||
if (!relativePath.startsWith('.')) {
|
||||
relativePath = `./${relativePath}`;
|
||||
}
|
||||
paths.push(relativePath);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-completion-provider.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-completion-provider.js","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-completion-provider.ts"],"names":[],"mappings":"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"}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/******************************************************************************
|
||||
* 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 type { DefinitionParams } from 'vscode-languageserver';
|
||||
import type { LangiumServices } from '../../lsp/lsp-services.js';
|
||||
import type { AstNode, LeafCstNode } from '../../syntax-tree.js';
|
||||
import type { MaybePromise } from '../../utils/promise-utils.js';
|
||||
import type { LangiumDocuments } from '../../workspace/documents.js';
|
||||
import type { Grammar } from '../../languages/generated/ast.js';
|
||||
import { LocationLink } from 'vscode-languageserver';
|
||||
import { DefaultDefinitionProvider } from '../../lsp/index.js';
|
||||
export declare class LangiumGrammarDefinitionProvider extends DefaultDefinitionProvider {
|
||||
protected documents: LangiumDocuments;
|
||||
constructor(services: LangiumServices);
|
||||
protected collectLocationLinks(sourceCstNode: LeafCstNode, _params: DefinitionParams): MaybePromise<LocationLink[] | undefined>;
|
||||
protected findTargetObject(importedGrammar: Grammar): AstNode | undefined;
|
||||
}
|
||||
//# sourceMappingURL=grammar-definition.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-definition.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-definition.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAS,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAM/D,qBAAa,gCAAiC,SAAQ,yBAAyB;IAE3E,SAAS,CAAC,SAAS,EAAE,gBAAgB,CAAC;gBAE1B,QAAQ,EAAE,eAAe;cAKlB,oBAAoB,CAAC,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,GAAG,YAAY,CAAC,YAAY,EAAE,GAAG,SAAS,CAAC;IAsBxI,SAAS,CAAC,gBAAgB,CAAC,eAAe,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS;CAO5E"}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************
|
||||
* 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 { LocationLink, Range } from 'vscode-languageserver';
|
||||
import { DefaultDefinitionProvider } from '../../lsp/index.js';
|
||||
import { streamContents } from '../../utils/ast-utils.js';
|
||||
import { findAssignment } from '../../utils/grammar-utils.js';
|
||||
import { isGrammarImport } from '../../languages/generated/ast.js';
|
||||
import { resolveImport } from '../internal-grammar-util.js';
|
||||
export class LangiumGrammarDefinitionProvider extends DefaultDefinitionProvider {
|
||||
constructor(services) {
|
||||
super(services);
|
||||
this.documents = services.shared.workspace.LangiumDocuments;
|
||||
}
|
||||
collectLocationLinks(sourceCstNode, _params) {
|
||||
const pathFeature = 'path';
|
||||
if (isGrammarImport(sourceCstNode.astNode) && findAssignment(sourceCstNode)?.feature === pathFeature) {
|
||||
const importedGrammar = resolveImport(this.documents, sourceCstNode.astNode);
|
||||
if (importedGrammar?.$document) {
|
||||
const targetObject = this.findTargetObject(importedGrammar) ?? importedGrammar;
|
||||
const selectionRange = this.nameProvider.getNameNode(targetObject)?.range ?? Range.create(0, 0, 0, 0);
|
||||
const previewRange = targetObject.$cstNode?.range ?? Range.create(0, 0, 0, 0);
|
||||
return [
|
||||
LocationLink.create(importedGrammar.$document.uri.toString(), previewRange, selectionRange, sourceCstNode.range)
|
||||
];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return super.collectLocationLinks(sourceCstNode, _params);
|
||||
}
|
||||
findTargetObject(importedGrammar) {
|
||||
// Jump to grammar name or the first element
|
||||
if (importedGrammar.isDeclared) {
|
||||
return importedGrammar;
|
||||
}
|
||||
return streamContents(importedGrammar).head();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-definition.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-definition.js","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-definition.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAQhF,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,OAAO,gCAAiC,SAAQ,yBAAyB;IAI3E,YAAY,QAAyB;QACjC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC;IAChE,CAAC;IAEkB,oBAAoB,CAAC,aAA0B,EAAE,OAAyB;QACzF,MAAM,WAAW,GAA8B,MAAM,CAAC;QACtD,IAAI,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC,aAAa,CAAC,EAAE,OAAO,KAAK,WAAW,EAAE,CAAC;YACnG,MAAM,eAAe,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;YAC7E,IAAI,eAAe,EAAE,SAAS,EAAE,CAAC;gBAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,IAAI,eAAe,CAAC;gBAC/E,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBACtG,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9E,OAAO;oBACH,YAAY,CAAC,MAAM,CACf,eAAe,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EACxC,YAAY,EACZ,cAAc,EACd,aAAa,CAAC,KAAK,CACtB;iBACJ,CAAC;YACN,CAAC;YACD,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,OAAO,KAAK,CAAC,oBAAoB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IAES,gBAAgB,CAAC,eAAwB;QAC/C,4CAA4C;QAC5C,IAAI,eAAe,CAAC,UAAU,EAAE,CAAC;YAC7B,OAAO,eAAe,CAAC;QAC3B,CAAC;QACD,OAAO,cAAc,CAAC,eAAe,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,CAAC;CACJ"}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import type { AstNode } from '../../syntax-tree.js';
|
||||
import { DefaultFoldingRangeProvider } from '../../lsp/folding-range-provider.js';
|
||||
/**
|
||||
* A specialized folding range provider for the grammar language
|
||||
*/
|
||||
export declare class LangiumGrammarFoldingRangeProvider extends DefaultFoldingRangeProvider {
|
||||
shouldProcessContent(node: AstNode): boolean;
|
||||
}
|
||||
//# sourceMappingURL=grammar-folding-ranges.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-folding-ranges.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-folding-ranges.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAGlF;;GAEG;AACH,qBAAa,kCAAmC,SAAQ,2BAA2B;IAEtE,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;CAIxD"}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/******************************************************************************
|
||||
* 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 { DefaultFoldingRangeProvider } from '../../lsp/folding-range-provider.js';
|
||||
import { isParserRule } from '../../languages/generated/ast.js';
|
||||
/**
|
||||
* A specialized folding range provider for the grammar language
|
||||
*/
|
||||
export class LangiumGrammarFoldingRangeProvider extends DefaultFoldingRangeProvider {
|
||||
shouldProcessContent(node) {
|
||||
// Exclude parser rules from folding
|
||||
return !isParserRule(node);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-folding-ranges.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-folding-ranges.js","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-folding-ranges.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAGhF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAEhE;;GAEG;AACH,MAAM,OAAO,kCAAmC,SAAQ,2BAA2B;IAEtE,oBAAoB,CAAC,IAAa;QACvC,oCAAoC;QACpC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACJ"}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/******************************************************************************
|
||||
* 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 type { AstNode } from '../../syntax-tree.js';
|
||||
import { AbstractFormatter } from '../../lsp/formatter.js';
|
||||
export declare class LangiumGrammarFormatter extends AbstractFormatter {
|
||||
protected format(node: AstNode): void;
|
||||
}
|
||||
//# sourceMappingURL=grammar-formatter.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-formatter.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-formatter.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAc,MAAM,wBAAwB,CAAC;AAKvE,qBAAa,uBAAwB,SAAQ,iBAAiB;IAE1D,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;CA0FxC"}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/******************************************************************************
|
||||
* 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 { AbstractFormatter, Formatting } from '../../lsp/formatter.js';
|
||||
import * as ast from '../../languages/generated/ast.js';
|
||||
const indentOrSpace = Formatting.fit(Formatting.oneSpace(), Formatting.indent());
|
||||
export class LangiumGrammarFormatter extends AbstractFormatter {
|
||||
format(node) {
|
||||
if (ast.isCrossReference(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.properties('type', 'terminal').surround(Formatting.noSpace());
|
||||
}
|
||||
else if (ast.isParserRule(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keywords('entry', 'fragment', 'returns').append(Formatting.oneSpace());
|
||||
if ((node.inferredType || node.returnType || node.dataType) && node.parameters.length === 0) {
|
||||
formatter.property('name').append(Formatting.oneSpace());
|
||||
}
|
||||
else {
|
||||
formatter.property('name').append(Formatting.noSpace());
|
||||
}
|
||||
formatter.properties('parameters').append(Formatting.noSpace());
|
||||
formatter.keywords(',').append(Formatting.oneSpace());
|
||||
formatter.keywords('<').append(Formatting.noSpace());
|
||||
const semicolon = formatter.keyword(';');
|
||||
const colon = formatter.keyword(':');
|
||||
colon.prepend(Formatting.noSpace());
|
||||
formatter.interior(colon, semicolon).prepend(Formatting.indent());
|
||||
semicolon.prepend(Formatting.fit(Formatting.noSpace(), Formatting.newLine()));
|
||||
formatter.node(node).prepend(Formatting.noIndent());
|
||||
}
|
||||
else if (ast.isTerminalRule(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
if (node.type) {
|
||||
formatter.property('name').append(Formatting.oneSpace());
|
||||
formatter.keyword('returns').append(Formatting.oneSpace());
|
||||
}
|
||||
formatter.keywords('hidden', 'terminal', 'fragment').append(Formatting.oneSpace());
|
||||
formatter.keyword(':').prepend(Formatting.noSpace());
|
||||
formatter.keyword(';').prepend(Formatting.fit(Formatting.noSpace(), Formatting.newLine()));
|
||||
formatter.node(node).prepend(Formatting.noIndent());
|
||||
}
|
||||
else if (ast.isAction(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keyword('{').append(Formatting.noSpace());
|
||||
formatter.keywords('.', '+=', '=').surround(Formatting.noSpace());
|
||||
formatter.keyword('}').prepend(Formatting.noSpace());
|
||||
}
|
||||
else if (ast.isInferredType(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keywords('infer', 'infers').append(Formatting.oneSpace());
|
||||
}
|
||||
else if (ast.isAssignment(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keywords('=', '+=', '?=').surround(Formatting.noSpace());
|
||||
}
|
||||
else if (ast.isRuleCall(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keyword('<').surround(Formatting.noSpace());
|
||||
formatter.keyword(',').append(Formatting.oneSpace());
|
||||
formatter.properties('arguments').append(Formatting.noSpace());
|
||||
}
|
||||
else if (ast.isInterface(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keyword('interface').append(Formatting.oneSpace());
|
||||
formatter.keyword('extends').prepend(Formatting.oneSpace()).append(indentOrSpace);
|
||||
formatter.keywords(',').prepend(Formatting.noSpace()).append(indentOrSpace);
|
||||
const bracesOpen = formatter.keyword('{');
|
||||
bracesOpen.prepend(Formatting.fit(Formatting.oneSpace(), Formatting.newLine()));
|
||||
const bracesClose = formatter.keyword('}');
|
||||
bracesClose.prepend(Formatting.newLine());
|
||||
formatter.interior(bracesOpen, bracesClose).prepend(Formatting.indent());
|
||||
}
|
||||
else if (ast.isType(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keyword('type').append(Formatting.oneSpace());
|
||||
formatter.keyword('=').prepend(Formatting.oneSpace()).append(indentOrSpace);
|
||||
formatter.keyword(';').prepend(Formatting.noSpace()).append(Formatting.newLine());
|
||||
}
|
||||
else if (ast.isGrammar(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
const nodes = formatter.nodes(...node.rules, ...node.interfaces, ...node.types, ...node.imports);
|
||||
nodes.prepend(Formatting.noIndent());
|
||||
formatter.keyword('grammar').prepend(Formatting.noSpace()).append(Formatting.oneSpace());
|
||||
}
|
||||
else if (ast.isInfixRuleOperatorList(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keywords('left', 'right').append(Formatting.oneSpace());
|
||||
formatter.keywords('|').surround(Formatting.oneSpace());
|
||||
}
|
||||
else if (ast.isInfixRuleOperators(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keywords('>').prepend(Formatting.newLine());
|
||||
}
|
||||
else if (ast.isInfixRule(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.keyword('infix').append(Formatting.oneSpace());
|
||||
formatter.keyword('on').append(Formatting.oneSpace());
|
||||
const semicolon = formatter.keyword(';');
|
||||
const colon = formatter.keyword(':');
|
||||
colon.prepend(Formatting.noSpace());
|
||||
formatter.interior(colon, semicolon).prepend(Formatting.indent());
|
||||
}
|
||||
if (ast.isAbstractElement(node)) {
|
||||
const formatter = this.getNodeFormatter(node);
|
||||
formatter.property('cardinality').prepend(Formatting.noSpace());
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-formatter.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+12
@@ -0,0 +1,12 @@
|
||||
/******************************************************************************
|
||||
* 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 type { AstNode } from '../../syntax-tree.js';
|
||||
import type { SemanticTokenAcceptor } from '../../lsp/semantic-token-provider.js';
|
||||
import { AbstractSemanticTokenProvider } from '../../lsp/semantic-token-provider.js';
|
||||
export declare class LangiumGrammarSemanticTokenProvider extends AbstractSemanticTokenProvider {
|
||||
protected highlightElement(node: AstNode, acceptor: SemanticTokenAcceptor): void;
|
||||
}
|
||||
//# sourceMappingURL=grammar-semantic-tokens.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-semantic-tokens.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-semantic-tokens.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAElF,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AAGrF,qBAAa,mCAAoC,SAAQ,6BAA6B;IAElF,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,qBAAqB,GAAG,IAAI;CA0DnF"}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/******************************************************************************
|
||||
* 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 { SemanticTokenTypes } from 'vscode-languageserver';
|
||||
import { AbstractSemanticTokenProvider } from '../../lsp/semantic-token-provider.js';
|
||||
import { isAction, isAssignment, isInfixRule, isParameter, isParameterReference, isReturnType, isRuleCall, isSimpleType, isTypeAttribute } from '../../languages/generated/ast.js';
|
||||
export class LangiumGrammarSemanticTokenProvider extends AbstractSemanticTokenProvider {
|
||||
highlightElement(node, acceptor) {
|
||||
if (isAssignment(node)) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'feature',
|
||||
type: SemanticTokenTypes.property
|
||||
});
|
||||
}
|
||||
else if (isAction(node)) {
|
||||
if (node.feature) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'feature',
|
||||
type: SemanticTokenTypes.property
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (isReturnType(node)) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'name',
|
||||
type: SemanticTokenTypes.type
|
||||
});
|
||||
}
|
||||
else if (isSimpleType(node)) {
|
||||
if (node.primitiveType || node.typeRef) {
|
||||
acceptor({
|
||||
node,
|
||||
property: node.primitiveType ? 'primitiveType' : 'typeRef',
|
||||
type: SemanticTokenTypes.type
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (isParameter(node)) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'name',
|
||||
type: SemanticTokenTypes.parameter
|
||||
});
|
||||
}
|
||||
else if (isParameterReference(node)) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'parameter',
|
||||
type: SemanticTokenTypes.parameter
|
||||
});
|
||||
}
|
||||
else if (isRuleCall(node)) {
|
||||
if (!isInfixRule(node.rule.ref) && node.rule.ref?.fragment) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'rule',
|
||||
type: SemanticTokenTypes.type
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (isTypeAttribute(node)) {
|
||||
acceptor({
|
||||
node,
|
||||
property: 'name',
|
||||
type: SemanticTokenTypes.property
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-semantic-tokens.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-semantic-tokens.js","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-semantic-tokens.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,oBAAoB,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAEnL,MAAM,OAAO,mCAAoC,SAAQ,6BAA6B;IAExE,gBAAgB,CAAC,IAAa,EAAE,QAA+B;QACrE,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,QAAQ,CAAC;gBACL,IAAI;gBACJ,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,kBAAkB,CAAC,QAAQ;aACpC,CAAC,CAAC;QACP,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,QAAQ,CAAC;oBACL,IAAI;oBACJ,QAAQ,EAAE,SAAS;oBACnB,IAAI,EAAE,kBAAkB,CAAC,QAAQ;iBACpC,CAAC,CAAC;YACP,CAAC;QACL,CAAC;aAAM,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,QAAQ,CAAC;gBACL,IAAI;gBACJ,QAAQ,EAAE,MAAM;gBAChB,IAAI,EAAE,kBAAkB,CAAC,IAAI;aAChC,CAAC,CAAC;QACP,CAAC;aAAM,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrC,QAAQ,CAAC;oBACL,IAAI;oBACJ,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;oBAC1D,IAAI,EAAE,kBAAkB,CAAC,IAAI;iBAChC,CAAC,CAAC;YACP,CAAC;QACL,CAAC;aAAM,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,QAAQ,CAAC;gBACL,IAAI;gBACJ,QAAQ,EAAE,MAAM;gBAChB,IAAI,EAAE,kBAAkB,CAAC,SAAS;aACrC,CAAC,CAAC;QACP,CAAC;aAAM,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC;gBACL,IAAI;gBACJ,QAAQ,EAAE,WAAW;gBACrB,IAAI,EAAE,kBAAkB,CAAC,SAAS;aACrC,CAAC,CAAC;QACP,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC;gBACzD,QAAQ,CAAC;oBACL,IAAI;oBACJ,QAAQ,EAAE,MAAM;oBAChB,IAAI,EAAE,kBAAkB,CAAC,IAAI;iBAChC,CAAC,CAAC;YACP,CAAC;QACL,CAAC;aAAM,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,QAAQ,CAAC;gBACL,IAAI;gBACJ,QAAQ,EAAE,MAAM;gBAChB,IAAI,EAAE,kBAAkB,CAAC,QAAQ;aACpC,CAAC,CAAC;QACP,CAAC;IACL,CAAC;CAEJ"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/******************************************************************************
|
||||
* 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 { AstNode } from '../../syntax-tree.js';
|
||||
import type { TypeHierarchyItem } from 'vscode-languageserver';
|
||||
import { AbstractTypeHierarchyProvider } from '../../lsp/type-hierarchy-provider.js';
|
||||
export declare class LangiumGrammarTypeHierarchyProvider extends AbstractTypeHierarchyProvider {
|
||||
protected getSupertypes(node: AstNode): TypeHierarchyItem[] | undefined;
|
||||
protected getSubtypes(node: AstNode): TypeHierarchyItem[] | undefined;
|
||||
}
|
||||
//# sourceMappingURL=grammar-type-hierarchy.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-type-hierarchy.d.ts","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-type-hierarchy.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AAKrF,qBAAa,mCAAoC,SAAQ,6BAA6B;IAClF,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,EAAE,GAAG,SAAS;IAiBvE,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,EAAE,GAAG,SAAS;CAmCxE"}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/******************************************************************************
|
||||
* 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 { AbstractTypeHierarchyProvider } from '../../lsp/type-hierarchy-provider.js';
|
||||
import { getDocument } from '../../utils/ast-utils.js';
|
||||
import { findLeafNodeAtOffset } from '../../utils/cst-utils.js';
|
||||
import { isInterface } from '../../languages/generated/ast.js';
|
||||
export class LangiumGrammarTypeHierarchyProvider extends AbstractTypeHierarchyProvider {
|
||||
getSupertypes(node) {
|
||||
if (!isInterface(node)) {
|
||||
return undefined;
|
||||
}
|
||||
const items = node.superTypes.flatMap(superType => {
|
||||
const ref = superType.ref;
|
||||
if (!ref) {
|
||||
return [];
|
||||
}
|
||||
return this.getTypeHierarchyItems(ref, getDocument(ref)) ?? [];
|
||||
});
|
||||
return items.length === 0 ? undefined : items;
|
||||
}
|
||||
getSubtypes(node) {
|
||||
if (!isInterface(node)) {
|
||||
return undefined;
|
||||
}
|
||||
const items = this.references
|
||||
.findReferences(node, { includeDeclaration: false })
|
||||
.flatMap(ref => {
|
||||
const document = this.documents.getDocument(ref.sourceUri);
|
||||
if (!document) {
|
||||
return [];
|
||||
}
|
||||
const rootNode = document.parseResult.value;
|
||||
if (!rootNode.$cstNode) {
|
||||
return [];
|
||||
}
|
||||
const refCstNode = findLeafNodeAtOffset(rootNode.$cstNode, ref.segment.offset);
|
||||
if (!refCstNode) {
|
||||
return [];
|
||||
}
|
||||
// Only consider references that occur as a superType of an interface
|
||||
const refNode = refCstNode.astNode;
|
||||
if (!isInterface(refNode) || refNode.superTypes.every(superType => superType.$refNode !== refCstNode)) {
|
||||
return [];
|
||||
}
|
||||
return this.getTypeHierarchyItems(refNode, document) ?? [];
|
||||
})
|
||||
.toArray();
|
||||
return items.length === 0 ? undefined : items;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-type-hierarchy.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-type-hierarchy.js","sourceRoot":"","sources":["../../../src/grammar/lsp/grammar-type-hierarchy.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAIhF,OAAO,EAAE,6BAA6B,EAAE,MAAM,sCAAsC,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAE/D,MAAM,OAAO,mCAAoC,SAAQ,6BAA6B;IACxE,aAAa,CAAC,IAAa;QACjC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;YAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC;YAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACP,OAAO,EAAE,CAAC;YACd,CAAC;YAED,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAClD,CAAC;IAES,WAAW,CAAC,IAAa;QAC/B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU;aACxB,cAAc,CAAC,IAAI,EAAE,EAAC,kBAAkB,EAAE,KAAK,EAAC,CAAC;aACjD,OAAO,CAAC,GAAG,CAAC,EAAE;YACX,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACZ,OAAO,EAAE,CAAC;YACd,CAAC;YAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC;YAC5C,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACrB,OAAO,EAAE,CAAC;YACd,CAAC;YAED,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC/E,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,OAAO,EAAE,CAAC;YACd,CAAC;YAED,qEAAqE;YACrE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC;YACnC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,UAAU,CAAC,EAAE,CAAC;gBACpG,OAAO,EAAE,CAAC;YACd,CAAC;YAED,OAAO,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/D,CAAC,CAAC;aACD,OAAO,EAAE,CAAC;QAEf,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAClD,CAAC;CACJ"}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/******************************************************************************
|
||||
* 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 type { AstNode, CstNode } from '../../syntax-tree.js';
|
||||
import { DefaultNameProvider } from '../../references/name-provider.js';
|
||||
export declare class LangiumGrammarNameProvider extends DefaultNameProvider {
|
||||
getName(node: AstNode): string | undefined;
|
||||
getNameNode(node: AstNode): CstNode | undefined;
|
||||
}
|
||||
//# sourceMappingURL=grammar-naming.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-naming.d.ts","sourceRoot":"","sources":["../../../src/grammar/references/grammar-naming.ts"],"names":[],"mappings":"AAAA;;;;+EAI+E;AAE/E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAIxE,qBAAa,0BAA2B,SAAQ,mBAAmB;IAEtD,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IAQ1C,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS;CAQ3D"}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/******************************************************************************
|
||||
* 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 { DefaultNameProvider } from '../../references/name-provider.js';
|
||||
import { findNodeForProperty } from '../../utils/grammar-utils.js';
|
||||
import { isAssignment } from '../../languages/generated/ast.js';
|
||||
export class LangiumGrammarNameProvider extends DefaultNameProvider {
|
||||
getName(node) {
|
||||
if (isAssignment(node)) {
|
||||
return node.feature;
|
||||
}
|
||||
else {
|
||||
return super.getName(node);
|
||||
}
|
||||
}
|
||||
getNameNode(node) {
|
||||
if (isAssignment(node)) {
|
||||
return findNodeForProperty(node.$cstNode, 'feature');
|
||||
}
|
||||
else {
|
||||
return super.getNameNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-naming.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-naming.js","sourceRoot":"","sources":["../../../src/grammar/references/grammar-naming.ts"],"names":[],"mappings":"AAAA;;;;+EAI+E;AAG/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAEhE,MAAM,OAAO,0BAA2B,SAAQ,mBAAmB;IAEtD,OAAO,CAAC,IAAa;QAC1B,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,OAAO,CAAC;QACxB,CAAC;aAAM,CAAC;YACJ,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACL,CAAC;IAEQ,WAAW,CAAC,IAAa;QAC9B,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,OAAO,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACJ,OAAO,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACL,CAAC;CAEJ"}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/******************************************************************************
|
||||
* Copyright 2021 TypeFox GmbH
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the MIT License, which is available in the project root.
|
||||
******************************************************************************/
|
||||
import type { AstNode, CstNode } from '../../syntax-tree.js';
|
||||
import type { Stream } from '../../utils/stream.js';
|
||||
import type { ReferenceDescription } from '../../workspace/ast-descriptions.js';
|
||||
import type { AbstractParserRule, Action, Assignment, Interface, Type, TypeAttribute } from '../../languages/generated/ast.js';
|
||||
import type { FindReferencesOptions } from '../../references/references.js';
|
||||
import { DefaultReferences } from '../../references/references.js';
|
||||
export declare class LangiumGrammarReferences extends DefaultReferences {
|
||||
findDeclarations(sourceCstNode: CstNode): AstNode[];
|
||||
findReferences(targetNode: AstNode, options: FindReferencesOptions): Stream<ReferenceDescription>;
|
||||
protected findReferencesToTypeAttribute(targetNode: TypeAttribute, includeDeclaration: boolean): Stream<ReferenceDescription>;
|
||||
protected createReferencesToAttribute(ruleOrAction: AbstractParserRule | Action, attribute: TypeAttribute): ReferenceDescription[];
|
||||
protected findAssignmentDeclaration(assignment: Assignment): AstNode | undefined;
|
||||
protected findActionDeclaration(action: Action, featureName?: string): TypeAttribute | undefined;
|
||||
protected findRulesWithReturnType(interf: Interface | Type): Array<AbstractParserRule | Action>;
|
||||
}
|
||||
//# sourceMappingURL=grammar-references.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-references.d.ts","sourceRoot":"","sources":["../../../src/grammar/references/grammar-references.ts"],"names":[],"mappings":"AAAA;;;;+EAI+E;AAE/E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAC/H,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAWnE,qBAAa,wBAAyB,SAAQ,iBAAiB;IAElD,gBAAgB,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,EAAE;IAgBnD,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAQ1G,SAAS,CAAC,6BAA6B,CAAC,UAAU,EAAE,aAAa,EAAE,kBAAkB,EAAE,OAAO,GAAG,MAAM,CAAC,oBAAoB,CAAC;IAqB7H,SAAS,CAAC,2BAA2B,CAAC,YAAY,EAAE,kBAAkB,GAAG,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,oBAAoB,EAAE;IAmElI,SAAS,CAAC,yBAAyB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS;IAuBhF,SAAS,CAAC,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAchG,SAAS,CAAC,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC,kBAAkB,GAAG,MAAM,CAAC;CAclG"}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/******************************************************************************
|
||||
* 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 { DefaultReferences } from '../../references/references.js';
|
||||
import { getContainerOfType, getDocument } from '../../utils/ast-utils.js';
|
||||
import { toDocumentSegment } from '../../utils/cst-utils.js';
|
||||
import { findAssignment, findNodeForKeyword, findNodeForProperty, getActionAtElement } from '../../utils/grammar-utils.js';
|
||||
import { stream } from '../../utils/stream.js';
|
||||
import { UriUtils } from '../../utils/uri-utils.js';
|
||||
import { isAbstractParserRule, isAction, isAssignment, isInfixRule, isInterface, isParserRule, isType, isTypeAttribute } from '../../languages/generated/ast.js';
|
||||
import { extractAssignments } from '../internal-grammar-util.js';
|
||||
import { collectChildrenTypes, collectSuperTypes } from '../type-system/types-util.js';
|
||||
import { assertUnreachable } from '../../utils/errors.js';
|
||||
export class LangiumGrammarReferences extends DefaultReferences {
|
||||
findDeclarations(sourceCstNode) {
|
||||
const nodeElem = sourceCstNode.astNode;
|
||||
const assignment = findAssignment(sourceCstNode);
|
||||
if (assignment && assignment.feature === 'feature') {
|
||||
// Only search for a special declaration if the cst node is the feature property of the action/assignment
|
||||
if (isAssignment(nodeElem)) {
|
||||
const decl = this.findAssignmentDeclaration(nodeElem);
|
||||
return decl ? [decl] : [];
|
||||
}
|
||||
else if (isAction(nodeElem)) {
|
||||
const decl = this.findActionDeclaration(nodeElem);
|
||||
return decl ? [decl] : [];
|
||||
}
|
||||
}
|
||||
return super.findDeclarations(sourceCstNode);
|
||||
}
|
||||
findReferences(targetNode, options) {
|
||||
if (isTypeAttribute(targetNode)) {
|
||||
return this.findReferencesToTypeAttribute(targetNode, options.includeDeclaration ?? false);
|
||||
}
|
||||
else {
|
||||
return super.findReferences(targetNode, options);
|
||||
}
|
||||
}
|
||||
findReferencesToTypeAttribute(targetNode, includeDeclaration) {
|
||||
const refs = [];
|
||||
const interfaceNode = getContainerOfType(targetNode, isInterface);
|
||||
if (interfaceNode) {
|
||||
if (includeDeclaration) {
|
||||
refs.push(...this.getSelfReferences(targetNode));
|
||||
}
|
||||
const interfaces = collectChildrenTypes(interfaceNode, this, this.documents, this.nodeLocator);
|
||||
const targetRules = [];
|
||||
interfaces.forEach(interf => {
|
||||
const rules = this.findRulesWithReturnType(interf);
|
||||
targetRules.push(...rules);
|
||||
});
|
||||
targetRules.forEach(rule => {
|
||||
const references = this.createReferencesToAttribute(rule, targetNode);
|
||||
refs.push(...references);
|
||||
});
|
||||
}
|
||||
return stream(refs);
|
||||
}
|
||||
createReferencesToAttribute(ruleOrAction, attribute) {
|
||||
const refs = [];
|
||||
if (isParserRule(ruleOrAction)) {
|
||||
const assignment = extractAssignments(ruleOrAction.definition).find(a => a.feature === attribute.name);
|
||||
if (assignment?.$cstNode) {
|
||||
const leaf = this.nameProvider.getNameNode(assignment);
|
||||
if (leaf) {
|
||||
const assignmentUri = getDocument(assignment).uri;
|
||||
const attributeUri = getDocument(attribute).uri;
|
||||
refs.push({
|
||||
sourceUri: assignmentUri,
|
||||
sourcePath: this.nodeLocator.getAstNodePath(assignment),
|
||||
targetUri: attributeUri,
|
||||
targetPath: this.nodeLocator.getAstNodePath(attribute),
|
||||
segment: toDocumentSegment(leaf),
|
||||
local: UriUtils.equals(assignmentUri, attributeUri)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isInfixRule(ruleOrAction)) {
|
||||
let leaf;
|
||||
if (attribute.name === 'left' || attribute.name === 'right') {
|
||||
// Use the 'on' keyword as segment
|
||||
leaf = findNodeForKeyword(ruleOrAction.$cstNode, 'on');
|
||||
}
|
||||
else if (attribute.name === 'operator') {
|
||||
// Use the rule definition in 'operators' as segment
|
||||
leaf = findNodeForProperty(ruleOrAction.$cstNode, 'operators');
|
||||
}
|
||||
if (leaf) {
|
||||
const ruleUri = getDocument(ruleOrAction).uri;
|
||||
const attributeUri = getDocument(attribute).uri;
|
||||
refs.push({
|
||||
sourceUri: ruleUri,
|
||||
sourcePath: this.nodeLocator.getAstNodePath(ruleOrAction),
|
||||
targetUri: attributeUri,
|
||||
targetPath: this.nodeLocator.getAstNodePath(attribute),
|
||||
segment: toDocumentSegment(leaf),
|
||||
local: UriUtils.equals(ruleUri, attributeUri)
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (isAction(ruleOrAction)) {
|
||||
// If the action references the attribute directly
|
||||
if (ruleOrAction.feature === attribute.name) {
|
||||
const leaf = findNodeForProperty(ruleOrAction.$cstNode, 'feature');
|
||||
if (leaf) {
|
||||
const actionUri = getDocument(ruleOrAction).uri;
|
||||
const attributeUri = getDocument(attribute).uri;
|
||||
refs.push({
|
||||
sourceUri: actionUri,
|
||||
sourcePath: this.nodeLocator.getAstNodePath(ruleOrAction),
|
||||
targetUri: attributeUri,
|
||||
targetPath: this.nodeLocator.getAstNodePath(attribute),
|
||||
segment: toDocumentSegment(leaf),
|
||||
local: UriUtils.equals(actionUri, attributeUri)
|
||||
});
|
||||
}
|
||||
}
|
||||
// Find all references within the parser rule that contains this action
|
||||
const parserRule = getContainerOfType(ruleOrAction, isParserRule);
|
||||
refs.push(...this.createReferencesToAttribute(parserRule, attribute));
|
||||
}
|
||||
else {
|
||||
assertUnreachable(ruleOrAction);
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
findAssignmentDeclaration(assignment) {
|
||||
const parserRule = getContainerOfType(assignment, isParserRule);
|
||||
const action = getActionAtElement(assignment);
|
||||
if (action) {
|
||||
const actionDeclaration = this.findActionDeclaration(action, assignment.feature);
|
||||
if (actionDeclaration) {
|
||||
return actionDeclaration;
|
||||
}
|
||||
}
|
||||
if (parserRule?.returnType?.ref) {
|
||||
if (isInterface(parserRule.returnType.ref) || isType(parserRule.returnType.ref)) {
|
||||
const interfaces = collectSuperTypes(parserRule.returnType.ref);
|
||||
for (const interf of interfaces) {
|
||||
const typeAttribute = interf.attributes.find(att => att.name === assignment.feature);
|
||||
if (typeAttribute) {
|
||||
return typeAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return assignment;
|
||||
}
|
||||
findActionDeclaration(action, featureName) {
|
||||
if (action.type?.ref) {
|
||||
const feature = featureName ?? action.feature;
|
||||
const interfaces = collectSuperTypes(action.type.ref);
|
||||
for (const interf of interfaces) {
|
||||
const typeAttribute = interf.attributes.find(att => att.name === feature);
|
||||
if (typeAttribute) {
|
||||
return typeAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
findRulesWithReturnType(interf) {
|
||||
const rules = [];
|
||||
const refs = this.index.findAllReferences(interf, this.nodeLocator.getAstNodePath(interf));
|
||||
for (const ref of refs) {
|
||||
const doc = this.documents.getDocument(ref.sourceUri);
|
||||
if (doc) {
|
||||
const astNode = this.nodeLocator.getAstNode(doc.parseResult.value, ref.sourcePath);
|
||||
if (isAbstractParserRule(astNode) || isAction(astNode)) {
|
||||
rules.push(astNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-references.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+41
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************
|
||||
* 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 { Scope } from '../../references/scope.js';
|
||||
import type { LangiumCoreServices } from '../../services.js';
|
||||
import type { AstNode, AstNodeDescription, ReferenceInfo } from '../../syntax-tree.js';
|
||||
import type { MultiMap } from '../../utils/collections.js';
|
||||
import type { AstNodeLocator } from '../../workspace/ast-node-locator.js';
|
||||
import type { LangiumDocument, LangiumDocuments } from '../../workspace/documents.js';
|
||||
import { DefaultScopeComputation } from '../../references/scope-computation.js';
|
||||
import { DefaultScopeProvider } from '../../references/scope-provider.js';
|
||||
export declare class LangiumGrammarScopeProvider extends DefaultScopeProvider {
|
||||
protected readonly langiumDocuments: LangiumDocuments;
|
||||
constructor(services: LangiumCoreServices);
|
||||
getScope(context: ReferenceInfo): Scope;
|
||||
private getNamedArgumentScope;
|
||||
private getTypeScope;
|
||||
protected getGlobalScope(referenceType: string, context: ReferenceInfo): Scope;
|
||||
private gatherImports;
|
||||
}
|
||||
export declare class LangiumGrammarScopeComputation extends DefaultScopeComputation {
|
||||
protected readonly astNodeLocator: AstNodeLocator;
|
||||
constructor(services: LangiumCoreServices);
|
||||
protected addExportedSymbol(node: AstNode, exports: AstNodeDescription[], document: LangiumDocument): void;
|
||||
protected addLocalSymbol(node: AstNode, document: LangiumDocument, symbols: MultiMap<AstNode, AstNodeDescription>): void;
|
||||
/**
|
||||
* Add synthetic type into the scope in case of explicitly or implicitly inferred type:<br>
|
||||
* cases: `ParserRule: ...;` or `ParserRule infers Type: ...;`
|
||||
*/
|
||||
protected processTypeNode(node: AstNode, document: LangiumDocument, symbols: MultiMap<AstNode, AstNodeDescription>): void;
|
||||
/**
|
||||
* Add synthetic type into the scope in case of explicitly inferred type:
|
||||
*
|
||||
* case: `{infer Action}`
|
||||
*/
|
||||
protected processActionNode(node: AstNode, document: LangiumDocument, symbols: MultiMap<AstNode, AstNodeDescription>): void;
|
||||
protected createInferredTypeDescription(node: AstNode, name: string, document?: LangiumDocument): AstNodeDescription;
|
||||
}
|
||||
//# sourceMappingURL=grammar-scope.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"grammar-scope.d.ts","sourceRoot":"","sources":["../../../src/grammar/references/grammar-scope.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EAAmB,eAAe,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGvG,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAM1E,qBAAa,2BAA4B,SAAQ,oBAAoB;IAEjE,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;gBAE1C,QAAQ,EAAE,mBAAmB;IAKhC,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,KAAK;IAYhD,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,YAAY;cAiBD,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,KAAK;IAcvF,OAAO,CAAC,aAAa;CAgBxB;AAED,qBAAa,8BAA+B,SAAQ,uBAAuB;IACvE,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;gBAEtC,QAAQ,EAAE,mBAAmB;cAKtB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI;cAkChG,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,GAAG,IAAI;IAUjI;;;OAGG;IACH,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,GAAG,IAAI;IAQzH;;;;OAIG;IACH,SAAS,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,GAAG,IAAI;IAO3H,SAAS,CAAC,6BAA6B,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,eAAmC,GAAG,kBAAkB;CAe1I"}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/******************************************************************************
|
||||
* 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 { EMPTY_SCOPE, MultiMapScope } from '../../references/scope.js';
|
||||
import { DefaultScopeComputation } from '../../references/scope-computation.js';
|
||||
import { DefaultScopeProvider } from '../../references/scope-provider.js';
|
||||
import { findRootNode, getContainerOfType, getDocument, streamAllContents } from '../../utils/ast-utils.js';
|
||||
import { toDocumentSegment } from '../../utils/cst-utils.js';
|
||||
import { AbstractType, InferredType, Interface, NamedArgument, Type, isAbstractParserRule, isAction, isGrammar, isReturnType, isRuleCall } from '../../languages/generated/ast.js';
|
||||
import { resolveImportUri } from '../internal-grammar-util.js';
|
||||
export class LangiumGrammarScopeProvider extends DefaultScopeProvider {
|
||||
constructor(services) {
|
||||
super(services);
|
||||
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
||||
}
|
||||
getScope(context) {
|
||||
if (context.container.$type === NamedArgument.$type && context.property === 'parameter') {
|
||||
return this.getNamedArgumentScope(context);
|
||||
}
|
||||
const referenceType = this.reflection.getReferenceType(context);
|
||||
if (referenceType === AbstractType.$type) {
|
||||
return this.getTypeScope(referenceType, context);
|
||||
}
|
||||
else {
|
||||
return super.getScope(context);
|
||||
}
|
||||
}
|
||||
getNamedArgumentScope(context) {
|
||||
const ruleCall = context.container.$container;
|
||||
if (!isRuleCall(ruleCall)) {
|
||||
return EMPTY_SCOPE;
|
||||
}
|
||||
const rule = ruleCall.rule.ref;
|
||||
if (!isAbstractParserRule(rule)) {
|
||||
return EMPTY_SCOPE;
|
||||
}
|
||||
return this.createScopeForNodes(rule.parameters);
|
||||
}
|
||||
getTypeScope(referenceType, context) {
|
||||
const localSymbols = getDocument(context.container).localSymbols;
|
||||
const rootNode = findRootNode(context.container);
|
||||
if (localSymbols && rootNode && localSymbols.has(rootNode)) {
|
||||
const globalScope = this.getGlobalScope(referenceType, context);
|
||||
const localScope = localSymbols.getStream(rootNode).filter(des => des.type === Interface.$type || des.type === Type.$type || des.type === InferredType.$type);
|
||||
return this.createScope(localScope, globalScope);
|
||||
}
|
||||
else {
|
||||
return this.getGlobalScope(referenceType, context);
|
||||
}
|
||||
}
|
||||
getGlobalScope(referenceType, context) {
|
||||
const grammar = getContainerOfType(context.container, isGrammar);
|
||||
if (!grammar) {
|
||||
return EMPTY_SCOPE;
|
||||
}
|
||||
const importedUris = new Set();
|
||||
this.gatherImports(grammar, importedUris);
|
||||
let importedElements = this.indexManager.allElements(referenceType, importedUris);
|
||||
if (referenceType === AbstractType.$type) {
|
||||
importedElements = importedElements.filter(des => des.type === Interface.$type || des.type === Type.$type || des.type === InferredType.$type);
|
||||
}
|
||||
return new MultiMapScope(importedElements);
|
||||
}
|
||||
gatherImports(grammar, importedUris) {
|
||||
for (const imp0rt of grammar.imports) {
|
||||
const uri = resolveImportUri(imp0rt);
|
||||
if (uri && !importedUris.has(uri.toString())) {
|
||||
importedUris.add(uri.toString());
|
||||
const importedDocument = this.langiumDocuments.getDocument(uri);
|
||||
if (importedDocument) {
|
||||
const rootNode = importedDocument.parseResult.value;
|
||||
if (isGrammar(rootNode)) {
|
||||
this.gatherImports(rootNode, importedUris);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export class LangiumGrammarScopeComputation extends DefaultScopeComputation {
|
||||
constructor(services) {
|
||||
super(services);
|
||||
this.astNodeLocator = services.workspace.AstNodeLocator;
|
||||
}
|
||||
addExportedSymbol(node, exports, document) {
|
||||
// this function is called in order to export nodes to the GLOBAL scope
|
||||
/* Among others, TYPES need to be exported.
|
||||
* There are three ways to define types:
|
||||
* - explicit "type" declarations
|
||||
* - explicit "interface" declarations
|
||||
* - "inferred types", which can be distinguished into ...
|
||||
* - inferred types with explicitly declared names, i.e. parser rules with "infers", actions with "infer"
|
||||
* Note, that multiple explicitly inferred types might have the same name! Cross-references to such types are resolved to the first declaration.
|
||||
* - implicitly inferred types, i.e. parser rules without "infers" and without "returns",
|
||||
* which implicitly declare a type with the same name as the parser rule
|
||||
* Note, that implicitly inferred types are unique, since names of parser rules must be unique.
|
||||
*/
|
||||
// export the top-level elements: parser rules, terminal rules, types, interfaces
|
||||
super.addExportedSymbol(node, exports, document);
|
||||
// additionally, export inferred types:
|
||||
if (isAbstractParserRule(node)) {
|
||||
if (!node.returnType && !node.dataType) {
|
||||
// Export implicitly and explicitly inferred type from parser rule
|
||||
const typeNode = node.inferredType ?? node;
|
||||
exports.push(this.createInferredTypeDescription(typeNode, typeNode.name, document));
|
||||
}
|
||||
streamAllContents(node).forEach(childNode => {
|
||||
if (isAction(childNode) && childNode.inferredType) {
|
||||
// Export explicitly inferred type from action
|
||||
exports.push(this.createInferredTypeDescription(childNode.inferredType, childNode.inferredType.name, document));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
addLocalSymbol(node, document, symbols) {
|
||||
// for the precompution of the local scope
|
||||
if (isReturnType(node)) {
|
||||
return;
|
||||
}
|
||||
this.processTypeNode(node, document, symbols);
|
||||
this.processActionNode(node, document, symbols);
|
||||
super.addLocalSymbol(node, document, symbols);
|
||||
}
|
||||
/**
|
||||
* Add synthetic type into the scope in case of explicitly or implicitly inferred type:<br>
|
||||
* cases: `ParserRule: ...;` or `ParserRule infers Type: ...;`
|
||||
*/
|
||||
processTypeNode(node, document, symbols) {
|
||||
const container = node.$container;
|
||||
if (container && isAbstractParserRule(node) && !node.returnType && !node.dataType) {
|
||||
const typeNode = node.inferredType ?? node;
|
||||
symbols.add(container, this.createInferredTypeDescription(typeNode, typeNode.name, document));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add synthetic type into the scope in case of explicitly inferred type:
|
||||
*
|
||||
* case: `{infer Action}`
|
||||
*/
|
||||
processActionNode(node, document, symbols) {
|
||||
const container = findRootNode(node);
|
||||
if (container && isAction(node) && node.inferredType) {
|
||||
symbols.add(container, this.createInferredTypeDescription(node.inferredType, node.inferredType.name, document));
|
||||
}
|
||||
}
|
||||
createInferredTypeDescription(node, name, document = getDocument(node)) {
|
||||
let nameNodeSegment;
|
||||
const nameSegmentGetter = () => nameNodeSegment ?? (nameNodeSegment = toDocumentSegment(this.nameProvider.getNameNode(node) ?? node.$cstNode));
|
||||
return {
|
||||
node,
|
||||
name,
|
||||
get nameSegment() {
|
||||
return nameSegmentGetter();
|
||||
},
|
||||
selectionSegment: toDocumentSegment(node.$cstNode),
|
||||
type: InferredType.$type,
|
||||
documentUri: document.uri,
|
||||
path: this.astNodeLocator.getAstNodePath(node)
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=grammar-scope.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+32
@@ -0,0 +1,32 @@
|
||||
/******************************************************************************
|
||||
* 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 { type Grammar } from '../../languages/generated/ast.js';
|
||||
import { type LangiumCoreServices } from '../../services.js';
|
||||
import type { ValidationAstTypes } from './type-collector/all-types.js';
|
||||
import type { PlainAstTypes } from './type-collector/plain-types.js';
|
||||
import type { AstTypes } from './type-collector/types.js';
|
||||
/**
|
||||
* Collects all types for the generated AST. The types collector entry point.
|
||||
*
|
||||
* @param grammars All grammars involved in the type generation process
|
||||
* @param config some optional configurations
|
||||
*/
|
||||
export declare function collectAst(grammars: Grammar | Grammar[], config?: {
|
||||
/** Langium core services to resolve imports as needed, and to pass along JSDoc comments to the generated AST */
|
||||
services?: LangiumCoreServices;
|
||||
filterNonAstTypeUnions?: boolean;
|
||||
}): AstTypes;
|
||||
/**
|
||||
* Collects all types used during the validation process.
|
||||
* The validation process requires us to compare our inferred types with our declared types.
|
||||
*
|
||||
* @param grammars All grammars involved in the validation process
|
||||
* @param services Langium core services to resolve imports as needed, and to pass along JSDoc comments to the generated AST
|
||||
*/
|
||||
export declare function collectValidationAst(grammars: Grammar | Grammar[], services?: LangiumCoreServices): ValidationAstTypes;
|
||||
export declare function createAstTypes(first: PlainAstTypes, second?: PlainAstTypes): AstTypes;
|
||||
export declare function specifyAstNodeProperties(astTypes: AstTypes): void;
|
||||
//# sourceMappingURL=ast-collector.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ast-collector.d.ts","sourceRoot":"","sources":["../../../src/grammar/type-system/ast-collector.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAChE,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAExE,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,iCAAiC,CAAC;AAEjG,OAAO,KAAK,EAAE,QAAQ,EAAsD,MAAM,2BAA2B,CAAC;AAI9G;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE,MAAM,CAAC,EAAE;IAC/D,gHAAgH;IAChH,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC,GAAG,QAAQ,CAOX;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,CAQtH;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,QAAQ,CASrF;AAaD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,QAM1D"}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/******************************************************************************
|
||||
* 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 {} from '../../languages/generated/ast.js';
|
||||
import {} from '../../services.js';
|
||||
import { collectTypeResources } from './type-collector/all-types.js';
|
||||
import { plainToTypes } from './type-collector/plain-types.js';
|
||||
import { isInterfaceType, isPrimitiveType, isPropertyUnion, isStringType, isUnionType, isValueType } from './type-collector/types.js';
|
||||
import { findAstTypes, isAstType } from './types-util.js';
|
||||
/**
|
||||
* Collects all types for the generated AST. The types collector entry point.
|
||||
*
|
||||
* @param grammars All grammars involved in the type generation process
|
||||
* @param config some optional configurations
|
||||
*/
|
||||
export function collectAst(grammars, config) {
|
||||
const { inferred, declared } = collectTypeResources(grammars, config?.services);
|
||||
const result = createAstTypes(inferred, declared);
|
||||
if (config?.filterNonAstTypeUnions) {
|
||||
result.unions = result.unions.filter(e => isAstType(e.type));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Collects all types used during the validation process.
|
||||
* The validation process requires us to compare our inferred types with our declared types.
|
||||
*
|
||||
* @param grammars All grammars involved in the validation process
|
||||
* @param services Langium core services to resolve imports as needed, and to pass along JSDoc comments to the generated AST
|
||||
*/
|
||||
export function collectValidationAst(grammars, services) {
|
||||
const { inferred, declared, astResources } = collectTypeResources(grammars, services);
|
||||
return {
|
||||
astResources,
|
||||
inferred: createAstTypes(declared, inferred),
|
||||
declared: createAstTypes(inferred, declared)
|
||||
};
|
||||
}
|
||||
export function createAstTypes(first, second) {
|
||||
const astTypes = {
|
||||
interfaces: mergeAndRemoveDuplicates(...first.interfaces, ...second?.interfaces ?? []),
|
||||
unions: mergeAndRemoveDuplicates(...first.unions, ...second?.unions ?? []),
|
||||
};
|
||||
const finalTypes = plainToTypes(astTypes);
|
||||
specifyAstNodeProperties(finalTypes);
|
||||
return finalTypes;
|
||||
}
|
||||
/**
|
||||
* Merges the lists of given elements into a single list and removes duplicates. Elements later in the lists get precedence over earlier elements.
|
||||
*
|
||||
* The distinction is performed over the `name` property of the element. The result is a name-sorted list of elements.
|
||||
*/
|
||||
function mergeAndRemoveDuplicates(...elements) {
|
||||
return Array.from(elements
|
||||
.reduce((acc, type) => { acc.set(type.name, type); return acc; }, new Map())
|
||||
.values()).sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
export function specifyAstNodeProperties(astTypes) {
|
||||
const nameToType = filterInterfaceLikeTypes(astTypes);
|
||||
const array = Array.from(nameToType.values());
|
||||
addSubTypes(array);
|
||||
buildContainerTypes(astTypes.interfaces);
|
||||
buildTypeNames(array);
|
||||
}
|
||||
function buildTypeNames(types) {
|
||||
// Recursively collect all subtype names
|
||||
const visited = new Set();
|
||||
const collect = (type) => {
|
||||
if (visited.has(type))
|
||||
return;
|
||||
visited.add(type);
|
||||
type.typeNames.add(type.name);
|
||||
for (const subtype of type.subTypes) {
|
||||
collect(subtype);
|
||||
subtype.typeNames.forEach(n => type.typeNames.add(n));
|
||||
}
|
||||
};
|
||||
types.forEach(collect);
|
||||
}
|
||||
/**
|
||||
* Removes union types that reference only to primitive types or
|
||||
* types that reference only to primitive types.
|
||||
*/
|
||||
function filterInterfaceLikeTypes({ interfaces, unions }) {
|
||||
const nameToType = interfaces.concat(unions)
|
||||
.reduce((acc, e) => { acc.set(e.name, e); return acc; }, new Map());
|
||||
const cache = new Map();
|
||||
for (const union of unions) {
|
||||
cache.set(union, isDataType(union.type, new Set()));
|
||||
}
|
||||
for (const [union, isDataType] of cache) {
|
||||
if (isDataType) {
|
||||
nameToType.delete(union.name);
|
||||
}
|
||||
}
|
||||
return nameToType;
|
||||
}
|
||||
function isDataType(property, visited) {
|
||||
if (visited.has(property)) {
|
||||
return true;
|
||||
}
|
||||
visited.add(property);
|
||||
if (isPropertyUnion(property)) {
|
||||
return property.types.every(e => isDataType(e, visited));
|
||||
}
|
||||
else if (isValueType(property)) {
|
||||
const value = property.value;
|
||||
if (isUnionType(value)) {
|
||||
return isDataType(value.type, visited);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return isPrimitiveType(property) || isStringType(property);
|
||||
}
|
||||
}
|
||||
function addSubTypes(types) {
|
||||
for (const interfaceType of types) {
|
||||
for (const superTypeName of interfaceType.superTypes) {
|
||||
superTypeName.subTypes.add(interfaceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Builds types of `$container` property.
|
||||
* @param interfaces Interfaces for which container types are calculated.
|
||||
*/
|
||||
function buildContainerTypes(interfaces) {
|
||||
const nameToInterface = interfaces
|
||||
.reduce((acc, type) => { acc.set(type.name, type); return acc; }, new Map());
|
||||
// 1st stage: collect container types
|
||||
for (const containerType of interfaces) {
|
||||
const types = containerType.properties.flatMap(property => findAstTypes(property.type));
|
||||
for (const type of types) {
|
||||
nameToInterface.get(type)?.containerTypes.add(containerType);
|
||||
}
|
||||
}
|
||||
// 2nd stage: lift the container types of containers to parents
|
||||
// if one of the children has no container types, the parent also loses container types
|
||||
// contains type names that have children and at least one of them has no container types
|
||||
const emptyContainerTypes = new Set();
|
||||
const queue = interfaces.filter(interf => interf.subTypes.size === 0);
|
||||
const visited = new Set(queue);
|
||||
while (queue.length > 0) {
|
||||
const interf = queue.shift();
|
||||
if (interf) {
|
||||
for (const superType of interf.superTypes) {
|
||||
if (isInterfaceType(superType)) {
|
||||
if (interf.containerTypes.size === 0) {
|
||||
emptyContainerTypes.add(superType.name);
|
||||
superType.containerTypes.clear();
|
||||
}
|
||||
else if (!emptyContainerTypes.has(superType.name)) {
|
||||
interf.containerTypes.forEach(e => superType.containerTypes.add(e));
|
||||
}
|
||||
if (!visited.has(superType)) {
|
||||
visited.add(superType);
|
||||
queue.push(superType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=ast-collector.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+13
@@ -0,0 +1,13 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
export * from './ast-collector.js';
|
||||
export * from './type-collector/types.js';
|
||||
export * from './type-collector/all-types.js';
|
||||
export * from './type-collector/declared-types.js';
|
||||
export * from './type-collector/inferred-types.js';
|
||||
export * from './type-collector/plain-types.js';
|
||||
export * from './types-util.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/grammar/type-system/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AACnD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iBAAiB,CAAC"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
export * from './ast-collector.js';
|
||||
export * from './type-collector/types.js';
|
||||
export * from './type-collector/all-types.js';
|
||||
export * from './type-collector/declared-types.js';
|
||||
export * from './type-collector/inferred-types.js';
|
||||
export * from './type-collector/plain-types.js';
|
||||
export * from './types-util.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/grammar/type-system/index.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AACnD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iBAAiB,CAAC"}
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* 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 type { ParserRule, Interface, Type, Grammar, InfixRule } from '../../../languages/generated/ast.js';
|
||||
import type { URI } from '../../../utils/uri-utils.js';
|
||||
import type { LangiumCoreServices } from '../../../index.js';
|
||||
import type { PlainAstTypes } from './plain-types.js';
|
||||
import type { AstTypes } from './types.js';
|
||||
export interface AstResources {
|
||||
parserRules: ParserRule[];
|
||||
infixRules: InfixRule[];
|
||||
datatypeRules: ParserRule[];
|
||||
interfaces: Interface[];
|
||||
types: Type[];
|
||||
}
|
||||
export interface TypeResources {
|
||||
inferred: PlainAstTypes;
|
||||
declared: PlainAstTypes;
|
||||
astResources: AstResources;
|
||||
}
|
||||
export interface ValidationAstTypes {
|
||||
inferred: AstTypes;
|
||||
declared: AstTypes;
|
||||
astResources: AstResources;
|
||||
}
|
||||
export declare function collectTypeResources(grammars: Grammar | Grammar[], services?: LangiumCoreServices): TypeResources;
|
||||
export declare function collectAllAstResources(grammars: Grammar | Grammar[], visited?: Set<URI>, astResources?: AstResources, services?: LangiumCoreServices): AstResources;
|
||||
//# sourceMappingURL=all-types.d.ts.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"all-types.d.ts","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/all-types.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAC3G,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQ3C,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,UAAU,EAAE,CAAA;IACzB,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,aAAa,EAAE,UAAU,EAAE,CAAA;IAC3B,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,KAAK,EAAE,IAAI,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,aAAa,CAAA;IACvB,YAAY,EAAE,YAAY,CAAA;CAC7B;AAED,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,EAAE,QAAQ,CAAA;IAClB,YAAY,EAAE,YAAY,CAAA;CAC7B;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAUjH;AAID,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE,OAAO,GAAE,GAAG,CAAC,GAAG,CAAa,EAC/F,YAAY,GAAE,YAAgG,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,YAAY,CA8BhK"}
|
||||
+55
@@ -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 { collectInferredTypes } from './inferred-types.js';
|
||||
import { collectDeclaredTypes } from './declared-types.js';
|
||||
import { getDocument } from '../../../utils/ast-utils.js';
|
||||
import { isInfixRule, isParserRule } from '../../../languages/generated/ast.js';
|
||||
import { resolveImport } from '../../internal-grammar-util.js';
|
||||
import { isDataTypeRule } from '../../../utils/grammar-utils.js';
|
||||
export function collectTypeResources(grammars, services) {
|
||||
const astResources = collectAllAstResources(grammars, undefined, undefined, services);
|
||||
const declared = collectDeclaredTypes(astResources.interfaces, astResources.types, services);
|
||||
const inferred = collectInferredTypes(astResources.parserRules, astResources.datatypeRules, astResources.infixRules, declared, services);
|
||||
return {
|
||||
astResources,
|
||||
inferred,
|
||||
declared
|
||||
};
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
export function collectAllAstResources(grammars, visited = new Set(), astResources = { parserRules: [], infixRules: [], datatypeRules: [], interfaces: [], types: [] }, services) {
|
||||
if (!Array.isArray(grammars))
|
||||
grammars = [grammars];
|
||||
for (const grammar of grammars) {
|
||||
const doc = getDocument(grammar);
|
||||
if (visited.has(doc.uri)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(doc.uri);
|
||||
for (const rule of grammar.rules) {
|
||||
if (isParserRule(rule) && !rule.fragment) {
|
||||
if (isDataTypeRule(rule)) {
|
||||
astResources.datatypeRules.push(rule);
|
||||
}
|
||||
else {
|
||||
astResources.parserRules.push(rule);
|
||||
}
|
||||
}
|
||||
else if (isInfixRule(rule)) {
|
||||
astResources.infixRules.push(rule);
|
||||
}
|
||||
}
|
||||
grammar.interfaces.forEach(e => astResources.interfaces.push(e));
|
||||
grammar.types.forEach(e => astResources.types.push(e));
|
||||
const documents = services?.shared.workspace.LangiumDocuments;
|
||||
if (documents) {
|
||||
const importedGrammars = grammar.imports.map(e => resolveImport(documents, e)).filter(e => e !== undefined);
|
||||
collectAllAstResources(importedGrammars, visited, astResources, services);
|
||||
}
|
||||
}
|
||||
return astResources;
|
||||
}
|
||||
//# sourceMappingURL=all-types.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"all-types.js","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/all-types.ts"],"names":[],"mappings":"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"}
|
||||
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
/******************************************************************************
|
||||
* 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 type { Interface, Type, TypeDefinition } from '../../../languages/generated/ast.js';
|
||||
import type { LangiumCoreServices } from '../../../index.js';
|
||||
import type { PlainAstTypes, PlainPropertyType } from './plain-types.js';
|
||||
export declare function collectDeclaredTypes(interfaces: Interface[], unions: Type[], services?: LangiumCoreServices): PlainAstTypes;
|
||||
export declare function typeDefinitionToPropertyType(type: TypeDefinition): PlainPropertyType;
|
||||
//# sourceMappingURL=declared-types.d.ts.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"declared-types.d.ts","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/declared-types.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAgB,MAAM,qCAAqC,CAAC;AACzG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,KAAK,EAAE,aAAa,EAA4D,iBAAiB,EAAc,MAAM,kBAAkB,CAAC;AAK/I,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAoD3H;AAYD,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,cAAc,GAAG,iBAAiB,CA8CpF"}
|
||||
Generated
Vendored
+124
@@ -0,0 +1,124 @@
|
||||
/******************************************************************************
|
||||
* 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 { isArrayLiteral, isBooleanLiteral } from '../../../languages/generated/ast.js';
|
||||
import { isArrayType, isReferenceType, isUnionType, isSimpleType } from '../../../languages/generated/ast.js';
|
||||
import { getTypeNameWithoutError, isPrimitiveGrammarType } from '../../internal-grammar-util.js';
|
||||
import { getTypeName } from '../../../utils/grammar-utils.js';
|
||||
export function collectDeclaredTypes(interfaces, unions, services) {
|
||||
const commentProvider = services?.documentation.CommentProvider;
|
||||
const declaredTypes = { unions: [], interfaces: [] };
|
||||
// add interfaces
|
||||
for (const type of interfaces) {
|
||||
const properties = [];
|
||||
for (const attribute of type.attributes) {
|
||||
const property = {
|
||||
name: attribute.name,
|
||||
optional: attribute.isOptional,
|
||||
astNodes: new Set([attribute]),
|
||||
type: typeDefinitionToPropertyType(attribute.type),
|
||||
comment: commentProvider?.getComment(attribute)
|
||||
};
|
||||
if (attribute.defaultValue) {
|
||||
property.defaultValue = toPropertyDefaultValue(attribute.defaultValue);
|
||||
}
|
||||
properties.push(property);
|
||||
}
|
||||
const superTypes = new Set();
|
||||
for (const superType of type.superTypes) {
|
||||
if (superType.ref) {
|
||||
superTypes.add(getTypeName(superType.ref));
|
||||
}
|
||||
}
|
||||
const interfaceType = {
|
||||
name: type.name,
|
||||
declared: true,
|
||||
abstract: false,
|
||||
properties: properties,
|
||||
superTypes: superTypes,
|
||||
subTypes: new Set(),
|
||||
comment: commentProvider?.getComment(type),
|
||||
};
|
||||
declaredTypes.interfaces.push(interfaceType);
|
||||
}
|
||||
// add types
|
||||
for (const union of unions) {
|
||||
const unionType = {
|
||||
name: union.name,
|
||||
declared: true,
|
||||
type: typeDefinitionToPropertyType(union.type),
|
||||
superTypes: new Set(),
|
||||
subTypes: new Set(),
|
||||
comment: commentProvider?.getComment(union),
|
||||
};
|
||||
declaredTypes.unions.push(unionType);
|
||||
}
|
||||
return declaredTypes;
|
||||
}
|
||||
function toPropertyDefaultValue(literal) {
|
||||
if (isBooleanLiteral(literal)) {
|
||||
return literal.true;
|
||||
}
|
||||
else if (isArrayLiteral(literal)) {
|
||||
return literal.elements.map(toPropertyDefaultValue);
|
||||
}
|
||||
else {
|
||||
return literal.value;
|
||||
}
|
||||
}
|
||||
export function typeDefinitionToPropertyType(type) {
|
||||
if (isArrayType(type)) {
|
||||
return {
|
||||
elementType: typeDefinitionToPropertyType(type.elementType)
|
||||
};
|
||||
}
|
||||
else if (isReferenceType(type)) {
|
||||
return {
|
||||
referenceType: typeDefinitionToPropertyType(type.referenceType),
|
||||
isMulti: type.isMulti,
|
||||
isSingle: !type.isMulti
|
||||
};
|
||||
}
|
||||
else if (isUnionType(type)) {
|
||||
return {
|
||||
types: type.types.map(typeDefinitionToPropertyType)
|
||||
};
|
||||
}
|
||||
else if (isSimpleType(type)) {
|
||||
let value;
|
||||
if (type.primitiveType) {
|
||||
value = type.primitiveType;
|
||||
return {
|
||||
primitive: value
|
||||
};
|
||||
}
|
||||
else if (type.stringType) {
|
||||
value = type.stringType;
|
||||
return {
|
||||
string: value
|
||||
};
|
||||
}
|
||||
else if (type.typeRef) {
|
||||
const ref = type.typeRef.ref;
|
||||
const value = getTypeNameWithoutError(ref);
|
||||
if (value) {
|
||||
if (isPrimitiveGrammarType(value)) {
|
||||
return {
|
||||
primitive: value
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
value
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
primitive: 'unknown'
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=declared-types.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"declared-types.js","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/declared-types.ts"],"names":[],"mappings":"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"}
|
||||
Generated
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
/******************************************************************************
|
||||
* 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 type { ParserRule, InfixRule } from '../../../languages/generated/ast.js';
|
||||
import type { PlainAstTypes } from './plain-types.js';
|
||||
import type { LangiumCoreServices } from '../../../index.js';
|
||||
export declare function collectInferredTypes(parserRules: ParserRule[], datatypeRules: ParserRule[], infixRules: InfixRule[], declared: PlainAstTypes, services?: LangiumCoreServices): PlainAstTypes;
|
||||
//# sourceMappingURL=inferred-types.d.ts.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"inferred-types.d.ts","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/inferred-types.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,UAAU,EAAiD,SAAS,EAAqC,MAAM,qCAAqC,CAAC;AACnK,OAAO,KAAK,EAAE,aAAa,EAAgE,MAAM,kBAAkB,CAAC;AACpH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAgQ7D,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,aAAa,CA+B5L"}
|
||||
Generated
Vendored
+742
@@ -0,0 +1,742 @@
|
||||
/******************************************************************************
|
||||
* 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 { isNamed } from '../../../references/name-provider.js';
|
||||
import { MultiMap } from '../../../utils/collections.js';
|
||||
import { isAlternatives, isKeyword, isParserRule, isAction, isGroup, isUnorderedGroup, isAssignment, isRuleCall, isCrossReference, isTerminalRule, isAbstractParserRule } from '../../../languages/generated/ast.js';
|
||||
import { getTypeNameWithoutError, isPrimitiveGrammarType } from '../../internal-grammar-util.js';
|
||||
import { mergePropertyTypes } from './plain-types.js';
|
||||
import { isOptionalCardinality, terminalRegex, getRuleTypeName, getTypeName } from '../../../utils/grammar-utils.js';
|
||||
class TypeGraph {
|
||||
constructor(context, root) {
|
||||
this.context = context;
|
||||
this.root = root;
|
||||
}
|
||||
getTypes() {
|
||||
return this.iterate(this.root, [{
|
||||
alt: {
|
||||
name: this.root.name,
|
||||
properties: this.root.properties,
|
||||
ruleCalls: this.root.ruleCalls,
|
||||
super: []
|
||||
},
|
||||
current: this.root,
|
||||
next: this.root.children
|
||||
}]);
|
||||
}
|
||||
iterate(root, paths) {
|
||||
const finished = paths.filter(e => e.next.length === 0);
|
||||
do {
|
||||
const next = this.recurse(root, paths);
|
||||
const unfinished = [];
|
||||
for (const path of next) {
|
||||
if (path.next.length > 0) {
|
||||
unfinished.push(path);
|
||||
}
|
||||
else {
|
||||
finished.push(path);
|
||||
}
|
||||
}
|
||||
paths = unfinished;
|
||||
} while (paths.length > 0);
|
||||
return finished;
|
||||
}
|
||||
recurse(root, paths, end) {
|
||||
const all = [];
|
||||
for (const path of paths) {
|
||||
const node = path.current;
|
||||
if (node !== end && node.children.length > 0) {
|
||||
const nextPaths = this.applyNext(root, path);
|
||||
const subPaths = this.recurse(root, nextPaths, node.end ?? end);
|
||||
all.push(...subPaths);
|
||||
}
|
||||
else {
|
||||
all.push(path);
|
||||
}
|
||||
}
|
||||
const map = new MultiMap();
|
||||
for (const path of all) {
|
||||
map.add(path.current, path);
|
||||
}
|
||||
const unique = [];
|
||||
for (const [node, groupedPaths] of map.entriesGroupedByKey()) {
|
||||
unique.push(...flattenTypes(groupedPaths, node));
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
applyNext(root, nextPath) {
|
||||
const splits = this.splitType(nextPath.alt, nextPath.next.length);
|
||||
const paths = [];
|
||||
for (let i = 0; i < nextPath.next.length; i++) {
|
||||
const split = splits[i];
|
||||
const part = nextPath.next[i];
|
||||
if (part.actionWithAssignment) {
|
||||
// If the path enters an action with an assignment which changes the current name
|
||||
// We already add a new path, since the next part of the part refers to a new inferred type
|
||||
paths.push({
|
||||
alt: copyTypeAlternative(split),
|
||||
current: part,
|
||||
next: [],
|
||||
comment: split.comment,
|
||||
});
|
||||
}
|
||||
if (part.name !== undefined && part.name !== split.name) {
|
||||
if (part.actionWithAssignment) {
|
||||
// We reset all properties, super types and ruleCalls since we are now in a new inferred type
|
||||
split.properties = [];
|
||||
split.ruleCalls = [];
|
||||
split.super = [root.name];
|
||||
split.name = part.name;
|
||||
}
|
||||
else {
|
||||
split.super = [split.name, ...split.ruleCalls];
|
||||
split.properties = [];
|
||||
split.ruleCalls = [];
|
||||
split.name = part.name;
|
||||
}
|
||||
}
|
||||
split.properties.push(...part.properties);
|
||||
split.ruleCalls.push(...part.ruleCalls);
|
||||
const path = {
|
||||
alt: split,
|
||||
current: part,
|
||||
next: part.children,
|
||||
comment: split.comment
|
||||
};
|
||||
path.alt.super = path.alt.super.filter(e => e !== path.alt.name);
|
||||
paths.push(path);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
splitType(type, count) {
|
||||
const alternatives = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
alternatives.push(copyTypeAlternative(type));
|
||||
}
|
||||
return alternatives;
|
||||
}
|
||||
getSuperTypes(node) {
|
||||
const set = new Set();
|
||||
this.collectSuperTypes(node, node, set);
|
||||
return Array.from(set);
|
||||
}
|
||||
collectSuperTypes(original, part, set) {
|
||||
if (part.ruleCalls.length > 0) {
|
||||
// Each unassigned rule call corresponds to a super type
|
||||
for (const ruleCall of part.ruleCalls) {
|
||||
set.add(ruleCall);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (const parent of part.parents) {
|
||||
if (original.name === undefined) {
|
||||
this.collectSuperTypes(parent, parent, set);
|
||||
}
|
||||
else if (parent.name !== undefined && parent.name !== original.name) {
|
||||
set.add(parent.name);
|
||||
}
|
||||
else {
|
||||
this.collectSuperTypes(original, parent, set);
|
||||
}
|
||||
}
|
||||
if (part.parents.length === 0 && part.name) {
|
||||
set.add(part.name);
|
||||
}
|
||||
}
|
||||
connect(parent, children) {
|
||||
children.parents.push(parent);
|
||||
parent.children.push(children);
|
||||
return children;
|
||||
}
|
||||
merge(...parts) {
|
||||
if (parts.length === 1) {
|
||||
return parts[0];
|
||||
}
|
||||
else if (parts.length === 0) {
|
||||
throw new Error('No parts to merge');
|
||||
}
|
||||
const node = newTypePart();
|
||||
node.parents = parts;
|
||||
for (const parent of parts) {
|
||||
parent.children.push(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
hasLeafNode(part) {
|
||||
return this.partHasLeafNode(part);
|
||||
}
|
||||
partHasLeafNode(part, ignore) {
|
||||
if (part.children.some(e => e !== ignore)) {
|
||||
return true;
|
||||
}
|
||||
else if (part.name) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return part.parents.some(e => this.partHasLeafNode(e, part));
|
||||
}
|
||||
}
|
||||
}
|
||||
function copyTypePart(value) {
|
||||
return {
|
||||
name: value.name,
|
||||
children: [],
|
||||
parents: [],
|
||||
actionWithAssignment: value.actionWithAssignment,
|
||||
ruleCalls: value.ruleCalls.slice(),
|
||||
properties: value.properties.map(copyProperty),
|
||||
};
|
||||
}
|
||||
function copyTypeAlternative(value) {
|
||||
return {
|
||||
name: value.name,
|
||||
super: value.super,
|
||||
ruleCalls: value.ruleCalls.slice(),
|
||||
properties: value.properties.map(e => copyProperty(e)),
|
||||
comment: value.comment,
|
||||
};
|
||||
}
|
||||
function copyProperty(value) {
|
||||
return {
|
||||
name: value.name,
|
||||
optional: value.optional,
|
||||
type: value.type,
|
||||
astNodes: value.astNodes,
|
||||
comment: value.comment,
|
||||
};
|
||||
}
|
||||
export function collectInferredTypes(parserRules, datatypeRules, infixRules, declared, services) {
|
||||
const commentProvider = services?.documentation.CommentProvider;
|
||||
// extract interfaces and types from parser rules
|
||||
const allTypes = [];
|
||||
const context = {
|
||||
fragments: new Map()
|
||||
};
|
||||
for (const rule of parserRules) {
|
||||
const comment = commentProvider?.getComment(rule);
|
||||
allTypes.push(...getRuleTypes(context, rule, services).map(typePath => ({ ...typePath, comment })));
|
||||
}
|
||||
const infixInterfaces = calculateInfixInterfaces(infixRules);
|
||||
const interfaces = calculateInterfaces(allTypes, infixInterfaces);
|
||||
const unions = buildSuperUnions(interfaces);
|
||||
const astTypes = extractUnions(interfaces, unions, declared);
|
||||
// extract types from datatype rules
|
||||
for (const rule of datatypeRules) {
|
||||
const type = getDataRuleType(rule);
|
||||
astTypes.unions.push({
|
||||
name: rule.name,
|
||||
declared: false,
|
||||
type,
|
||||
subTypes: new Set(),
|
||||
superTypes: new Set(),
|
||||
dataType: rule.dataType,
|
||||
comment: commentProvider?.getComment(rule),
|
||||
});
|
||||
}
|
||||
return astTypes;
|
||||
}
|
||||
function calculateInfixInterfaces(rules) {
|
||||
const interfaces = [];
|
||||
for (const infixRule of rules) {
|
||||
const on = infixRule.call.rule.ref;
|
||||
const onName = isAbstractParserRule(on) ? getTypeName(on) : on?.name;
|
||||
if (onName && infixRule.name) {
|
||||
const operators = infixRule.operators.precedences
|
||||
.flatMap(e => e.operators).map(e => e.value).sort();
|
||||
const expressionProperty = {
|
||||
astNodes: new Set(),
|
||||
optional: false,
|
||||
type: {
|
||||
value: onName
|
||||
}
|
||||
};
|
||||
const interfaceType = {
|
||||
name: getTypeName(infixRule),
|
||||
declared: false,
|
||||
abstract: false,
|
||||
properties: [
|
||||
{
|
||||
...expressionProperty,
|
||||
name: 'left'
|
||||
},
|
||||
{
|
||||
...expressionProperty,
|
||||
name: 'right'
|
||||
},
|
||||
{
|
||||
name: 'operator',
|
||||
astNodes: new Set(),
|
||||
optional: false,
|
||||
type: {
|
||||
types: operators.map(operator => ({
|
||||
string: operator
|
||||
}))
|
||||
}
|
||||
}
|
||||
],
|
||||
subTypes: new Set(),
|
||||
superTypes: new Set()
|
||||
};
|
||||
interfaces.push(interfaceType);
|
||||
}
|
||||
}
|
||||
return interfaces;
|
||||
}
|
||||
function getDataRuleType(rule) {
|
||||
if (rule.dataType && rule.dataType !== 'string') {
|
||||
return {
|
||||
primitive: rule.dataType
|
||||
};
|
||||
}
|
||||
let cancelled = false;
|
||||
const cancel = () => {
|
||||
cancelled = true;
|
||||
return {
|
||||
primitive: 'unknown'
|
||||
};
|
||||
};
|
||||
const type = buildDataRuleType(rule.definition, cancel);
|
||||
if (cancelled) {
|
||||
return {
|
||||
primitive: 'string'
|
||||
};
|
||||
}
|
||||
else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
function buildDataRuleType(element, cancel) {
|
||||
if (element.cardinality) {
|
||||
// Multiplicity/optionality is not supported for types
|
||||
return cancel();
|
||||
}
|
||||
if (isAlternatives(element)) {
|
||||
return {
|
||||
types: element.elements.map(e => buildDataRuleType(e, cancel))
|
||||
};
|
||||
}
|
||||
else if (isGroup(element) || isUnorderedGroup(element)) {
|
||||
if (element.elements.length !== 1) {
|
||||
return cancel();
|
||||
}
|
||||
else {
|
||||
return buildDataRuleType(element.elements[0], cancel);
|
||||
}
|
||||
}
|
||||
else if (isRuleCall(element)) {
|
||||
const ref = element.rule?.ref;
|
||||
if (ref) {
|
||||
if (isTerminalRule(ref)) {
|
||||
let regex;
|
||||
try {
|
||||
regex = terminalRegex(ref).toString();
|
||||
}
|
||||
catch {
|
||||
// If the regex cannot be built, we assume it's just a string
|
||||
regex = undefined;
|
||||
}
|
||||
return {
|
||||
primitive: ref.type?.name ?? 'string',
|
||||
regex
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
value: ref.name
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return cancel();
|
||||
}
|
||||
}
|
||||
else if (isKeyword(element)) {
|
||||
return {
|
||||
string: element.value
|
||||
};
|
||||
}
|
||||
return cancel();
|
||||
}
|
||||
function getRuleTypes(context, rule, services) {
|
||||
const type = newTypePart(rule);
|
||||
const graph = new TypeGraph(context, type);
|
||||
if (rule.definition) {
|
||||
type.end = collectElement(graph, graph.root, rule.definition, services);
|
||||
}
|
||||
return flattenTypes(graph.getTypes(), type.end ?? newTypePart());
|
||||
}
|
||||
function newTypePart(element) {
|
||||
return {
|
||||
name: isAbstractParserRule(element) || isAction(element) ? getTypeNameWithoutError(element) : element,
|
||||
properties: [],
|
||||
ruleCalls: [],
|
||||
children: [],
|
||||
parents: [],
|
||||
actionWithAssignment: false
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Collects all possible type branches of a given parser rule element.
|
||||
*
|
||||
* @param state State to walk over element's graph.
|
||||
* @param type Element that collects a current type branch for the given element.
|
||||
* @param element The given AST element, from which it's necessary to extract the type.
|
||||
*/
|
||||
function collectElement(graph, current, element, services) {
|
||||
const optional = isOptionalCardinality(element.cardinality, element);
|
||||
if (isAlternatives(element)) {
|
||||
const children = [];
|
||||
if (optional) {
|
||||
// Create a new empty node
|
||||
children.push(graph.connect(current, newTypePart()));
|
||||
}
|
||||
for (const alt of element.elements) {
|
||||
const altType = graph.connect(current, newTypePart());
|
||||
children.push(collectElement(graph, altType, alt, services));
|
||||
}
|
||||
const mergeNode = graph.merge(...children);
|
||||
current.end = mergeNode;
|
||||
return mergeNode;
|
||||
}
|
||||
else if (isGroup(element) || isUnorderedGroup(element)) {
|
||||
let groupNode = graph.connect(current, newTypePart());
|
||||
let skipNode;
|
||||
if (optional) {
|
||||
skipNode = graph.connect(current, newTypePart());
|
||||
}
|
||||
for (const item of element.elements) {
|
||||
groupNode = collectElement(graph, groupNode, item, services);
|
||||
}
|
||||
if (skipNode) {
|
||||
const mergeNode = graph.merge(skipNode, groupNode);
|
||||
current.end = mergeNode;
|
||||
return mergeNode;
|
||||
}
|
||||
else {
|
||||
return groupNode;
|
||||
}
|
||||
}
|
||||
else if (isAction(element)) {
|
||||
return addAction(graph, current, element, services);
|
||||
}
|
||||
else if (isAssignment(element)) {
|
||||
addAssignment(current, element, services);
|
||||
}
|
||||
else if (isRuleCall(element)) {
|
||||
addRuleCall(graph, current, element, services);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
function addAction(graph, parent, action, services) {
|
||||
const commentProvider = services?.documentation.CommentProvider;
|
||||
// We create a copy of the current type part
|
||||
// This is essentially a leaf node of the current type
|
||||
// Otherwise we might lose information, such as properties
|
||||
// We do this if there's no leaf node for the current type yet
|
||||
if (!graph.hasLeafNode(parent)) {
|
||||
const copy = copyTypePart(parent);
|
||||
graph.connect(parent, copy);
|
||||
}
|
||||
const typeNode = graph.connect(parent, newTypePart(action));
|
||||
if (action.type) {
|
||||
const type = action.type?.ref;
|
||||
if (type && isNamed(type))
|
||||
// cs: if the (named) type could be resolved properly also set the name on 'typeNode'
|
||||
// for the sake of completeness and better comprehensibility during debugging,
|
||||
// it's not supposed to have a effect on the flow of control!
|
||||
typeNode.name = type.name;
|
||||
}
|
||||
if (action.feature && action.operator) {
|
||||
typeNode.actionWithAssignment = true;
|
||||
typeNode.properties.push({
|
||||
name: action.feature,
|
||||
optional: false,
|
||||
type: toPropertyType(action.operator === '+=', undefined, graph.root.ruleCalls.length !== 0 ? graph.root.ruleCalls : graph.getSuperTypes(typeNode)),
|
||||
astNodes: new Set([action]),
|
||||
comment: commentProvider?.getComment(action),
|
||||
});
|
||||
}
|
||||
return typeNode;
|
||||
}
|
||||
function addAssignment(current, assignment, services) {
|
||||
const commentProvider = services?.documentation.CommentProvider;
|
||||
const typeItems = { types: new Set() };
|
||||
findTypes(assignment.terminal, typeItems);
|
||||
const type = toPropertyType(assignment.operator === '+=', typeItems.reference, assignment.operator === '?=' ? ['boolean'] : Array.from(typeItems.types));
|
||||
current.properties.push({
|
||||
name: assignment.feature,
|
||||
optional: isOptionalCardinality(assignment.cardinality),
|
||||
type,
|
||||
astNodes: new Set([assignment]),
|
||||
comment: commentProvider?.getComment(assignment),
|
||||
});
|
||||
}
|
||||
function findTypes(terminal, types) {
|
||||
if (isAlternatives(terminal) || isUnorderedGroup(terminal) || isGroup(terminal)) {
|
||||
for (const element of terminal.elements) {
|
||||
findTypes(element, types);
|
||||
}
|
||||
}
|
||||
else if (isKeyword(terminal)) {
|
||||
types.types.add(`'${terminal.value}'`);
|
||||
}
|
||||
else if (isRuleCall(terminal) && terminal.rule.ref) {
|
||||
types.types.add(getRuleTypeName(terminal.rule.ref));
|
||||
}
|
||||
else if (isCrossReference(terminal) && terminal.type.ref) {
|
||||
const refTypeName = getTypeNameWithoutError(terminal.type.ref);
|
||||
if (refTypeName) {
|
||||
types.types.add(refTypeName);
|
||||
}
|
||||
types.reference ?? (types.reference = {});
|
||||
if (terminal.isMulti) {
|
||||
types.reference.isMulti = true;
|
||||
}
|
||||
else {
|
||||
types.reference.isSingle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
function addRuleCall(graph, current, ruleCall, services) {
|
||||
const rule = ruleCall.rule.ref;
|
||||
// Add all properties of fragments to the current type
|
||||
if (isParserRule(rule) && rule.fragment) {
|
||||
const properties = getFragmentProperties(rule, graph.context, services);
|
||||
if (isOptionalCardinality(ruleCall.cardinality)) {
|
||||
current.properties.push(...properties.map(e => ({
|
||||
...e,
|
||||
optional: true
|
||||
})));
|
||||
}
|
||||
else {
|
||||
current.properties.push(...properties);
|
||||
}
|
||||
}
|
||||
else if (isAbstractParserRule(rule)) {
|
||||
current.ruleCalls.push(getRuleTypeName(rule));
|
||||
}
|
||||
}
|
||||
function getFragmentProperties(fragment, context, services) {
|
||||
const existing = context.fragments.get(fragment);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const properties = [];
|
||||
context.fragments.set(fragment, properties);
|
||||
const fragmentName = getTypeNameWithoutError(fragment);
|
||||
const typeAlternatives = getRuleTypes(context, fragment, services).filter(e => e.alt.name === fragmentName);
|
||||
properties.push(...typeAlternatives.flatMap(e => e.alt.properties));
|
||||
return properties;
|
||||
}
|
||||
/**
|
||||
* Calculate interfaces from all possible type branches.
|
||||
* [some of these interfaces will become types in the generated AST]
|
||||
* @param alternatives The type branches that will be squashed in interfaces.
|
||||
* @returns Interfaces.
|
||||
*/
|
||||
function calculateInterfaces(alternatives, otherInterfaces) {
|
||||
const interfaces = new Map(otherInterfaces.map(e => [e.name, e]));
|
||||
const ruleCallAlternatives = [];
|
||||
const flattened = alternatives.length > 0
|
||||
? flattenTypes(alternatives, alternatives[0].current).map(e => e.alt)
|
||||
: [];
|
||||
for (const flat of flattened) {
|
||||
const interfaceType = {
|
||||
name: flat.name,
|
||||
properties: flat.properties,
|
||||
superTypes: new Set(flat.super),
|
||||
subTypes: new Set(),
|
||||
declared: false,
|
||||
abstract: false,
|
||||
comment: flat.comment,
|
||||
};
|
||||
interfaces.set(interfaceType.name, interfaceType);
|
||||
if (flat.ruleCalls.length > 0) {
|
||||
ruleCallAlternatives.push(flat);
|
||||
flat.ruleCalls.forEach(e => {
|
||||
if (e !== interfaceType.name) { // An interface cannot subtype itself
|
||||
interfaceType.subTypes.add(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
// all other cases assume we have a data type rule
|
||||
// we do not generate an AST type for data type rules
|
||||
}
|
||||
for (const ruleCallType of ruleCallAlternatives) {
|
||||
for (const ruleCall of ruleCallType.ruleCalls) {
|
||||
const calledInterface = interfaces.get(ruleCall);
|
||||
if (calledInterface) {
|
||||
if (calledInterface.name !== ruleCallType.name) {
|
||||
calledInterface.superTypes.add(ruleCallType.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(interfaces.values());
|
||||
}
|
||||
function flattenTypes(alternatives, part) {
|
||||
var _a;
|
||||
const nameToAlternatives = alternatives.reduce((acc, e) => acc.add(e.alt.name, e), new MultiMap());
|
||||
const types = [];
|
||||
for (const [name, namedAlternatives] of nameToAlternatives.entriesGroupedByKey()) {
|
||||
const properties = [];
|
||||
const ruleCalls = new Set();
|
||||
const type = { alt: { name, properties, ruleCalls: [], super: [] }, next: [], current: part };
|
||||
for (const path of namedAlternatives) {
|
||||
const alt = path.alt;
|
||||
type.comment ?? (type.comment = path.comment);
|
||||
(_a = type.alt).comment ?? (_a.comment = path.comment);
|
||||
type.alt.super.push(...alt.super);
|
||||
type.next.push(...path.next);
|
||||
const altProperties = alt.properties;
|
||||
for (const altProperty of altProperties) {
|
||||
const existingProperty = properties.find(e => e.name === altProperty.name);
|
||||
if (existingProperty) {
|
||||
existingProperty.type = mergePropertyTypes(existingProperty.type, altProperty.type);
|
||||
altProperty.astNodes.forEach(e => existingProperty.astNodes.add(e));
|
||||
}
|
||||
else {
|
||||
properties.push({ ...altProperty });
|
||||
}
|
||||
}
|
||||
alt.ruleCalls.forEach(ruleCall => ruleCalls.add(ruleCall));
|
||||
}
|
||||
for (const path of namedAlternatives) {
|
||||
type.next = Array.from(new Set(type.next));
|
||||
const alt = path.alt;
|
||||
// A type with rule calls is not a real member of the type
|
||||
// Any missing properties are therefore not associated with the current type
|
||||
if (alt.ruleCalls.length === 0) {
|
||||
for (const property of properties) {
|
||||
if (!alt.properties.find(e => e.name === property.name)) {
|
||||
property.optional = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
type.alt.ruleCalls = Array.from(ruleCalls);
|
||||
types.push(type);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
function buildSuperUnions(interfaces) {
|
||||
const interfaceMap = new Map(interfaces.map(e => [e.name, e]));
|
||||
const unions = [];
|
||||
const allSupertypes = new MultiMap();
|
||||
for (const interfaceType of interfaces) {
|
||||
for (const superType of interfaceType.superTypes) {
|
||||
allSupertypes.add(superType, interfaceType.name);
|
||||
}
|
||||
}
|
||||
for (const [superType, types] of allSupertypes.entriesGroupedByKey()) {
|
||||
if (!interfaceMap.has(superType)) {
|
||||
const union = {
|
||||
declared: false,
|
||||
name: superType,
|
||||
subTypes: new Set(),
|
||||
superTypes: new Set(),
|
||||
type: toPropertyType(false, undefined, types)
|
||||
};
|
||||
unions.push(union);
|
||||
}
|
||||
}
|
||||
return unions;
|
||||
}
|
||||
/**
|
||||
* Filters interfaces, transforming some of them in unions.
|
||||
* The transformation criterion: no properties, but have subtypes.
|
||||
* @param interfaces The interfaces that have to be transformed on demand.
|
||||
* @returns Types and not transformed interfaces.
|
||||
*/
|
||||
function extractUnions(interfaces, unions, declared) {
|
||||
const subTypes = new MultiMap();
|
||||
for (const interfaceType of interfaces) {
|
||||
for (const superTypeName of interfaceType.superTypes) {
|
||||
subTypes.add(superTypeName, interfaceType.name);
|
||||
}
|
||||
}
|
||||
const declaredInterfaces = new Set(declared.interfaces.map(e => e.name));
|
||||
const astTypes = { interfaces: [], unions };
|
||||
const unionTypes = new Map(unions.map(e => [e.name, e]));
|
||||
for (const interfaceType of interfaces) {
|
||||
const interfaceSubTypes = new Set(subTypes.get(interfaceType.name));
|
||||
// Convert an interface into a union type if it has subtypes and no properties on its own
|
||||
if (interfaceType.properties.length === 0 && interfaceSubTypes.size > 0) {
|
||||
// In case we have an explicitly declared interface
|
||||
// Mark the interface as `abstract` and do not create a union type
|
||||
if (declaredInterfaces.has(interfaceType.name)) {
|
||||
interfaceType.abstract = true;
|
||||
astTypes.interfaces.push(interfaceType);
|
||||
}
|
||||
else {
|
||||
const interfaceTypeValue = toPropertyType(false, undefined, Array.from(interfaceSubTypes));
|
||||
const existingUnion = unionTypes.get(interfaceType.name);
|
||||
if (existingUnion) {
|
||||
existingUnion.type = mergePropertyTypes(existingUnion.type, interfaceTypeValue);
|
||||
}
|
||||
else {
|
||||
const unionType = {
|
||||
name: interfaceType.name,
|
||||
declared: false,
|
||||
subTypes: interfaceSubTypes,
|
||||
superTypes: interfaceType.superTypes,
|
||||
type: interfaceTypeValue,
|
||||
comment: interfaceType.comment,
|
||||
};
|
||||
astTypes.unions.push(unionType);
|
||||
unionTypes.set(interfaceType.name, unionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
astTypes.interfaces.push(interfaceType);
|
||||
}
|
||||
}
|
||||
// After converting some interfaces into union types, these interfaces are no longer valid super types
|
||||
for (const interfaceType of astTypes.interfaces) {
|
||||
interfaceType.superTypes = new Set([...interfaceType.superTypes].filter(superType => !unionTypes.has(superType)));
|
||||
}
|
||||
return astTypes;
|
||||
}
|
||||
function toPropertyType(array, reference, types) {
|
||||
if (array) {
|
||||
return {
|
||||
elementType: toPropertyType(false, reference, types)
|
||||
};
|
||||
}
|
||||
else if (reference) {
|
||||
const isMulti = reference.isMulti ?? false;
|
||||
const isSingle = reference.isSingle ?? !isMulti;
|
||||
return {
|
||||
referenceType: toPropertyType(false, undefined, types),
|
||||
isMulti,
|
||||
isSingle
|
||||
};
|
||||
}
|
||||
else if (types.length === 1) {
|
||||
const type = types[0];
|
||||
if (type.startsWith("'")) {
|
||||
return {
|
||||
string: type.substring(1, type.length - 1)
|
||||
};
|
||||
}
|
||||
if (isPrimitiveGrammarType(type)) {
|
||||
return {
|
||||
primitive: type
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
value: type
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
types: types.map(e => toPropertyType(false, undefined, [e]))
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=inferred-types.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+76
@@ -0,0 +1,76 @@
|
||||
/******************************************************************************
|
||||
* 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 type { Action, Assignment, TypeAttribute } from '../../../languages/generated/ast.js';
|
||||
import type { AstTypes } from './types.js';
|
||||
export interface PlainAstTypes {
|
||||
interfaces: PlainInterface[];
|
||||
unions: PlainUnion[];
|
||||
}
|
||||
export type PlainType = PlainInterface | PlainUnion;
|
||||
export interface PlainInterface {
|
||||
name: string;
|
||||
superTypes: Set<string>;
|
||||
subTypes: Set<string>;
|
||||
properties: PlainProperty[];
|
||||
declared: boolean;
|
||||
abstract: boolean;
|
||||
comment?: string;
|
||||
}
|
||||
export declare function isPlainInterface(type: PlainType): type is PlainInterface;
|
||||
export interface PlainUnion {
|
||||
name: string;
|
||||
superTypes: Set<string>;
|
||||
subTypes: Set<string>;
|
||||
type: PlainPropertyType;
|
||||
declared: boolean;
|
||||
dataType?: string;
|
||||
comment?: string;
|
||||
}
|
||||
export declare function isPlainUnion(type: PlainType): type is PlainUnion;
|
||||
export interface PlainProperty {
|
||||
name: string;
|
||||
optional: boolean;
|
||||
astNodes: Set<Assignment | Action | TypeAttribute>;
|
||||
type: PlainPropertyType;
|
||||
defaultValue?: PlainPropertyDefaultValue;
|
||||
comment?: string;
|
||||
}
|
||||
export type PlainPropertyDefaultValue = string | number | boolean | PlainPropertyDefaultValue[];
|
||||
export type PlainPropertyType = PlainReferenceType | PlainArrayType | PlainPropertyUnion | PlainValueType | PlainPrimitiveType | PlainStringType;
|
||||
export interface PlainReferenceType {
|
||||
referenceType: PlainPropertyType;
|
||||
isMulti: boolean;
|
||||
isSingle: boolean;
|
||||
}
|
||||
export declare function isPlainReferenceType(propertyType: PlainPropertyType): propertyType is PlainReferenceType;
|
||||
export interface PlainArrayType {
|
||||
elementType: PlainPropertyType;
|
||||
}
|
||||
export declare function isPlainArrayType(propertyType: PlainPropertyType): propertyType is PlainArrayType;
|
||||
export interface PlainPropertyUnion {
|
||||
types: PlainPropertyType[];
|
||||
}
|
||||
export declare function isPlainPropertyUnion(propertyType: PlainPropertyType): propertyType is PlainPropertyUnion;
|
||||
export interface PlainValueType {
|
||||
value: string;
|
||||
}
|
||||
export declare function isPlainValueType(propertyType: PlainPropertyType): propertyType is PlainValueType;
|
||||
export interface PlainPrimitiveType {
|
||||
primitive: string;
|
||||
regex?: string;
|
||||
}
|
||||
export declare function isPlainPrimitiveType(propertyType: PlainPropertyType): propertyType is PlainPrimitiveType;
|
||||
export interface PlainStringType {
|
||||
string: string;
|
||||
}
|
||||
export declare function isPlainStringType(propertyType: PlainPropertyType): propertyType is PlainStringType;
|
||||
export declare function plainToTypes(plain: PlainAstTypes): AstTypes;
|
||||
export declare function mergePropertyTypes(first: PlainPropertyType, second: PlainPropertyType): PlainPropertyType;
|
||||
export declare function flattenPlainType(type: PlainPropertyType): {
|
||||
union: PlainPropertyType[];
|
||||
array: PlainPropertyType[];
|
||||
};
|
||||
//# sourceMappingURL=plain-types.d.ts.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"plain-types.d.ts","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/plain-types.ts"],"names":[],"mappings":"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"}
|
||||
Generated
Vendored
+220
@@ -0,0 +1,220 @@
|
||||
/******************************************************************************
|
||||
* 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 { hasBooleanType } from '../types-util.js';
|
||||
import { InterfaceType, UnionType, isArrayType } from './types.js';
|
||||
export function isPlainInterface(type) {
|
||||
return !isPlainUnion(type);
|
||||
}
|
||||
export function isPlainUnion(type) {
|
||||
return 'type' in type;
|
||||
}
|
||||
export function isPlainReferenceType(propertyType) {
|
||||
return 'referenceType' in propertyType;
|
||||
}
|
||||
export function isPlainArrayType(propertyType) {
|
||||
return 'elementType' in propertyType;
|
||||
}
|
||||
export function isPlainPropertyUnion(propertyType) {
|
||||
return 'types' in propertyType;
|
||||
}
|
||||
export function isPlainValueType(propertyType) {
|
||||
return 'value' in propertyType;
|
||||
}
|
||||
export function isPlainPrimitiveType(propertyType) {
|
||||
return 'primitive' in propertyType;
|
||||
}
|
||||
export function isPlainStringType(propertyType) {
|
||||
return 'string' in propertyType;
|
||||
}
|
||||
export function plainToTypes(plain) {
|
||||
const interfaceTypes = new Map();
|
||||
const unionTypes = new Map();
|
||||
for (const interfaceValue of plain.interfaces) {
|
||||
const type = new InterfaceType(interfaceValue.name, interfaceValue.declared, interfaceValue.abstract, interfaceValue.comment);
|
||||
interfaceTypes.set(interfaceValue.name, type);
|
||||
}
|
||||
for (const unionValue of plain.unions) {
|
||||
const type = new UnionType(unionValue.name, {
|
||||
declared: unionValue.declared,
|
||||
dataType: unionValue.dataType,
|
||||
comment: unionValue.comment,
|
||||
});
|
||||
unionTypes.set(unionValue.name, type);
|
||||
}
|
||||
for (const interfaceValue of plain.interfaces) {
|
||||
const type = interfaceTypes.get(interfaceValue.name);
|
||||
for (const superTypeName of interfaceValue.superTypes) {
|
||||
const superType = interfaceTypes.get(superTypeName) || unionTypes.get(superTypeName);
|
||||
if (superType) {
|
||||
type.superTypes.add(superType);
|
||||
}
|
||||
}
|
||||
for (const subTypeName of interfaceValue.subTypes) {
|
||||
const subType = interfaceTypes.get(subTypeName) || unionTypes.get(subTypeName);
|
||||
if (subType) {
|
||||
type.subTypes.add(subType);
|
||||
}
|
||||
}
|
||||
for (const property of interfaceValue.properties) {
|
||||
const prop = plainToProperty(property, interfaceTypes, unionTypes);
|
||||
type.properties.push(prop);
|
||||
}
|
||||
}
|
||||
for (const unionValue of plain.unions) {
|
||||
const type = unionTypes.get(unionValue.name);
|
||||
type.type = plainToPropertyType(unionValue.type, type, interfaceTypes, unionTypes);
|
||||
}
|
||||
return {
|
||||
interfaces: Array.from(interfaceTypes.values()),
|
||||
unions: Array.from(unionTypes.values())
|
||||
};
|
||||
}
|
||||
function plainToProperty(property, interfaces, unions) {
|
||||
const prop = {
|
||||
name: property.name,
|
||||
optional: property.optional,
|
||||
astNodes: property.astNodes,
|
||||
type: plainToPropertyType(property.type, undefined, interfaces, unions),
|
||||
comment: property.comment,
|
||||
};
|
||||
if (property.defaultValue !== undefined) {
|
||||
prop.defaultValue = property.defaultValue;
|
||||
}
|
||||
else if (hasBooleanType(prop.type)) {
|
||||
prop.defaultValue = false;
|
||||
}
|
||||
else if (isArrayType(prop.type)) {
|
||||
prop.defaultValue = [];
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
function plainToPropertyType(type, union, interfaces, unions) {
|
||||
if (isPlainArrayType(type)) {
|
||||
return {
|
||||
elementType: plainToPropertyType(type.elementType, union, interfaces, unions)
|
||||
};
|
||||
}
|
||||
else if (isPlainReferenceType(type)) {
|
||||
return {
|
||||
referenceType: plainToPropertyType(type.referenceType, undefined, interfaces, unions),
|
||||
isMulti: type.isMulti,
|
||||
isSingle: type.isSingle
|
||||
};
|
||||
}
|
||||
else if (isPlainPropertyUnion(type)) {
|
||||
return {
|
||||
types: type.types.map(e => plainToPropertyType(e, union, interfaces, unions))
|
||||
};
|
||||
}
|
||||
else if (isPlainStringType(type)) {
|
||||
return {
|
||||
string: type.string
|
||||
};
|
||||
}
|
||||
else if (isPlainPrimitiveType(type)) {
|
||||
return {
|
||||
primitive: type.primitive,
|
||||
regex: type.regex
|
||||
};
|
||||
}
|
||||
else if (isPlainValueType(type)) {
|
||||
const value = interfaces.get(type.value) || unions.get(type.value);
|
||||
if (!value) {
|
||||
return {
|
||||
primitive: 'unknown'
|
||||
};
|
||||
}
|
||||
if (union) {
|
||||
union.subTypes.add(value);
|
||||
}
|
||||
return {
|
||||
value
|
||||
};
|
||||
}
|
||||
else {
|
||||
throw new Error('Invalid property type');
|
||||
}
|
||||
}
|
||||
export function mergePropertyTypes(first, second) {
|
||||
const { union: flattenedFirstUnion, array: flattenedFirstArray } = flattenPlainType(first);
|
||||
const { union: flattenedSecondUnion, array: flattenedSecondArray } = flattenPlainType(second);
|
||||
const flattenedUnion = mergeTypeUnion(flattenedFirstUnion, flattenedSecondUnion);
|
||||
const flattenedArray = mergeTypeUnion(flattenedFirstArray, flattenedSecondArray);
|
||||
if (flattenedArray.length > 0) {
|
||||
flattenedUnion.push({
|
||||
elementType: flattenedArray.length === 1 ? flattenedArray[0] : {
|
||||
types: flattenedArray
|
||||
}
|
||||
});
|
||||
}
|
||||
if (flattenedUnion.length === 1) {
|
||||
return flattenedUnion[0];
|
||||
}
|
||||
else {
|
||||
return {
|
||||
types: flattenedUnion
|
||||
};
|
||||
}
|
||||
}
|
||||
function mergeTypeUnion(first, second) {
|
||||
const result = [...first];
|
||||
for (const type of second) {
|
||||
if (!includesType(result, type)) {
|
||||
result.push(type);
|
||||
}
|
||||
else if (isPlainReferenceType(type)) {
|
||||
// Adjust the existing reference type to also include the multi/single flags of the new type
|
||||
const existing = result.find((e) => isPlainReferenceType(e) && typeEquals(e.referenceType, type.referenceType));
|
||||
if (existing) {
|
||||
existing.isMulti || (existing.isMulti = type.isMulti);
|
||||
existing.isSingle || (existing.isSingle = type.isSingle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function includesType(list, value) {
|
||||
return list.some(e => typeEquals(e, value));
|
||||
}
|
||||
function typeEquals(first, second) {
|
||||
if (isPlainArrayType(first) && isPlainArrayType(second)) {
|
||||
return typeEquals(first.elementType, second.elementType);
|
||||
}
|
||||
else if (isPlainReferenceType(first) && isPlainReferenceType(second)) {
|
||||
return typeEquals(first.referenceType, second.referenceType);
|
||||
}
|
||||
else if (isPlainValueType(first) && isPlainValueType(second)) {
|
||||
return first.value === second.value;
|
||||
}
|
||||
else if (isPlainPrimitiveType(first) && isPlainPrimitiveType(second)) {
|
||||
return first.primitive === second.primitive;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function flattenPlainType(type) {
|
||||
if (isPlainPropertyUnion(type)) {
|
||||
const flattened = type.types.flatMap(e => flattenPlainType(e));
|
||||
return {
|
||||
union: flattened.map(e => e.union).flat(),
|
||||
array: flattened.map(e => e.array).flat()
|
||||
};
|
||||
}
|
||||
else if (isPlainArrayType(type)) {
|
||||
return {
|
||||
array: flattenPlainType(type.elementType).union,
|
||||
union: []
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
array: [],
|
||||
union: [type]
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=plain-types.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
+96
@@ -0,0 +1,96 @@
|
||||
/******************************************************************************
|
||||
* 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 type { CstNode } from '../../../syntax-tree.js';
|
||||
import type { Action, Assignment, TypeAttribute } from '../../../languages/generated/ast.js';
|
||||
export interface Property {
|
||||
name: string;
|
||||
optional: boolean;
|
||||
type: PropertyType;
|
||||
defaultValue?: PropertyDefaultValue;
|
||||
astNodes: Set<Assignment | Action | TypeAttribute>;
|
||||
comment?: string;
|
||||
}
|
||||
export type PropertyDefaultValue = string | number | boolean | PropertyDefaultValue[];
|
||||
export type PropertyType = ReferenceType | ArrayType | PropertyUnion | ValueType | PrimitiveType | StringType;
|
||||
export interface ReferenceType {
|
||||
referenceType: PropertyType;
|
||||
isMulti: boolean;
|
||||
isSingle: boolean;
|
||||
}
|
||||
export declare function isReferenceType(propertyType: PropertyType): propertyType is ReferenceType;
|
||||
export interface ArrayType {
|
||||
elementType: PropertyType | undefined;
|
||||
}
|
||||
export declare function isArrayType(propertyType: PropertyType): propertyType is ArrayType;
|
||||
export interface PropertyUnion {
|
||||
types: PropertyType[];
|
||||
}
|
||||
export declare function isPropertyUnion(propertyType: PropertyType): propertyType is PropertyUnion;
|
||||
export declare function flattenPropertyUnion(propertyType: PropertyType): PropertyType[];
|
||||
export interface ValueType {
|
||||
value: TypeOption;
|
||||
}
|
||||
export declare function isValueType(propertyType: PropertyType): propertyType is ValueType;
|
||||
export interface PrimitiveType {
|
||||
primitive: string;
|
||||
regex?: string;
|
||||
}
|
||||
export declare function isPrimitiveType(propertyType: PropertyType): propertyType is PrimitiveType;
|
||||
export interface StringType {
|
||||
string: string;
|
||||
}
|
||||
export declare function isStringType(propertyType: PropertyType): propertyType is StringType;
|
||||
export type AstTypes = {
|
||||
interfaces: InterfaceType[];
|
||||
unions: UnionType[];
|
||||
};
|
||||
export declare function isUnionType(type: TypeOption): type is UnionType;
|
||||
export declare function isInterfaceType(type: TypeOption): type is InterfaceType;
|
||||
export type TypeOption = InterfaceType | UnionType;
|
||||
export declare class UnionType {
|
||||
name: string;
|
||||
type: PropertyType;
|
||||
superTypes: Set<TypeOption>;
|
||||
subTypes: Set<TypeOption>;
|
||||
typeNames: Set<string>;
|
||||
declared: boolean;
|
||||
dataType?: string;
|
||||
comment?: string;
|
||||
constructor(name: string, options?: {
|
||||
declared: boolean;
|
||||
dataType?: string;
|
||||
comment?: string;
|
||||
});
|
||||
toAstTypesString(reflectionInfo: boolean): string;
|
||||
toDeclaredTypesString(reservedWords: Set<string>): string;
|
||||
}
|
||||
export declare class InterfaceType {
|
||||
name: string;
|
||||
comment?: string;
|
||||
superTypes: Set<TypeOption>;
|
||||
subTypes: Set<TypeOption>;
|
||||
containerTypes: Set<TypeOption>;
|
||||
typeNames: Set<string>;
|
||||
declared: boolean;
|
||||
abstract: boolean;
|
||||
properties: Property[];
|
||||
get superProperties(): Property[];
|
||||
private getSuperProperties;
|
||||
get allProperties(): Property[];
|
||||
private getSubTypeProperties;
|
||||
get interfaceSuperTypes(): InterfaceType[];
|
||||
constructor(name: string, declared: boolean, abstract: boolean, comment?: string);
|
||||
toAstTypesString(reflectionInfo: boolean): string;
|
||||
toDeclaredTypesString(reservedWords: Set<string>): string;
|
||||
}
|
||||
export declare class TypeResolutionError extends Error {
|
||||
readonly target: CstNode | undefined;
|
||||
constructor(message: string, target: CstNode | undefined);
|
||||
}
|
||||
export declare function isTypeAssignable(from: PropertyType, to: PropertyType): boolean;
|
||||
export declare function propertyTypeToString(type?: PropertyType, mode?: 'AstType' | 'DeclaredType'): string;
|
||||
export declare function isMandatoryPropertyType(propertyType: PropertyType): boolean;
|
||||
//# sourceMappingURL=types.d.ts.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/grammar/type-system/type-collector/types.ts"],"names":[],"mappings":"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"}
|
||||
+503
@@ -0,0 +1,503 @@
|
||||
/******************************************************************************
|
||||
* 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 { expandToNode, expandToStringWithNL, joinToNode, toString } from '../../../generate/index.js';
|
||||
import { distinctAndSorted, escapeQuotes } from '../types-util.js';
|
||||
export function isReferenceType(propertyType) {
|
||||
return 'referenceType' in propertyType;
|
||||
}
|
||||
export function isArrayType(propertyType) {
|
||||
return 'elementType' in propertyType;
|
||||
}
|
||||
export function isPropertyUnion(propertyType) {
|
||||
return 'types' in propertyType;
|
||||
}
|
||||
export function flattenPropertyUnion(propertyType) {
|
||||
if (isPropertyUnion(propertyType)) {
|
||||
const items = [];
|
||||
for (const type of propertyType.types) {
|
||||
items.push(...flattenPropertyUnion(type));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
else {
|
||||
return [propertyType];
|
||||
}
|
||||
}
|
||||
export function isValueType(propertyType) {
|
||||
return 'value' in propertyType;
|
||||
}
|
||||
export function isPrimitiveType(propertyType) {
|
||||
return 'primitive' in propertyType;
|
||||
}
|
||||
export function isStringType(propertyType) {
|
||||
return 'string' in propertyType;
|
||||
}
|
||||
export function isUnionType(type) {
|
||||
return type && 'type' in type;
|
||||
}
|
||||
export function isInterfaceType(type) {
|
||||
return type && 'properties' in type;
|
||||
}
|
||||
export class UnionType {
|
||||
constructor(name, options) {
|
||||
this.superTypes = new Set();
|
||||
this.subTypes = new Set();
|
||||
this.typeNames = new Set();
|
||||
this.name = name;
|
||||
this.declared = options?.declared ?? false;
|
||||
this.dataType = options?.dataType;
|
||||
this.comment = options?.comment;
|
||||
}
|
||||
toAstTypesString(reflectionInfo) {
|
||||
const unionNode = expandToNode `${this.comment}`
|
||||
.appendNewLineIfNotEmpty()
|
||||
.append(`export type ${this.name} = ${propertyTypeToString(this.type, 'AstType')};`)
|
||||
.appendNewLine();
|
||||
if (reflectionInfo) {
|
||||
unionNode.appendNewLine()
|
||||
.append(addReflectionInfo(this.name));
|
||||
}
|
||||
if (this.dataType) {
|
||||
unionNode.appendNewLine()
|
||||
.append(addDataTypeReflectionInfo(this));
|
||||
}
|
||||
return toString(unionNode);
|
||||
}
|
||||
toDeclaredTypesString(reservedWords) {
|
||||
return expandToStringWithNL `
|
||||
type ${escapeReservedWords(this.name, reservedWords)} = ${propertyTypeToString(this.type, 'DeclaredType')};
|
||||
`;
|
||||
}
|
||||
}
|
||||
export class InterfaceType {
|
||||
get superProperties() {
|
||||
return this.getSuperProperties(new Set());
|
||||
}
|
||||
getSuperProperties(visited) {
|
||||
if (visited.has(this.name)) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
visited.add(this.name);
|
||||
}
|
||||
const map = new Map();
|
||||
for (const property of this.properties) {
|
||||
map.set(property.name, property);
|
||||
}
|
||||
for (const superType of this.interfaceSuperTypes) {
|
||||
const allSuperProperties = superType.getSuperProperties(visited);
|
||||
for (const superProp of allSuperProperties) {
|
||||
if (!map.has(superProp.name)) {
|
||||
map.set(superProp.name, superProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from(map.values());
|
||||
}
|
||||
get allProperties() {
|
||||
const map = new Map(this.superProperties.map(e => [e.name, e]));
|
||||
for (const subType of this.subTypes) {
|
||||
this.getSubTypeProperties(subType, map, new Set());
|
||||
}
|
||||
const superProps = Array.from(map.values());
|
||||
return superProps;
|
||||
}
|
||||
getSubTypeProperties(type, map, visited) {
|
||||
if (visited.has(this.name)) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
visited.add(this.name);
|
||||
}
|
||||
const props = isInterfaceType(type) ? type.properties : [];
|
||||
for (const prop of props) {
|
||||
if (!map.has(prop.name)) {
|
||||
map.set(prop.name, prop);
|
||||
}
|
||||
}
|
||||
for (const subType of type.subTypes) {
|
||||
this.getSubTypeProperties(subType, map, visited);
|
||||
}
|
||||
}
|
||||
get interfaceSuperTypes() {
|
||||
return Array.from(this.superTypes).filter(e => e instanceof InterfaceType);
|
||||
}
|
||||
constructor(name, declared, abstract, comment) {
|
||||
this.superTypes = new Set();
|
||||
this.subTypes = new Set();
|
||||
this.containerTypes = new Set();
|
||||
this.typeNames = new Set();
|
||||
this.declared = false;
|
||||
this.abstract = false;
|
||||
this.properties = [];
|
||||
this.name = name;
|
||||
this.declared = declared;
|
||||
this.abstract = abstract;
|
||||
this.comment = comment;
|
||||
}
|
||||
toAstTypesString(reflectionInfo) {
|
||||
const interfaceSuperTypes = this.interfaceSuperTypes.map(e => e.name);
|
||||
const superTypes = interfaceSuperTypes.length > 0 ? distinctAndSorted([...interfaceSuperTypes]) : ['langium.AstNode'];
|
||||
const interfaceNode = expandToNode `${this.comment}`
|
||||
.appendNewLineIfNotEmpty()
|
||||
.append(`export interface ${this.name} extends ${superTypes.join(', ')} {`)
|
||||
.appendNewLine();
|
||||
interfaceNode.indent(body => {
|
||||
if (this.containerTypes.size > 0) {
|
||||
body.append(`readonly $container: ${distinctAndSorted([...this.containerTypes].map(e => e.name)).join(' | ')};`).appendNewLine();
|
||||
}
|
||||
if (this.typeNames.size > 0) {
|
||||
body.append(`readonly $type: ${distinctAndSorted([...this.typeNames]).map(e => `'${e}'`).join(' | ')};`).appendNewLine();
|
||||
}
|
||||
body.append(pushProperties(this.properties, 'AstType'));
|
||||
});
|
||||
interfaceNode.append('}').appendNewLine();
|
||||
if (reflectionInfo) {
|
||||
interfaceNode
|
||||
.appendNewLine()
|
||||
.append(addReflectionInfo(this.name, this.superProperties));
|
||||
}
|
||||
return toString(interfaceNode);
|
||||
}
|
||||
toDeclaredTypesString(reservedWords) {
|
||||
const name = escapeReservedWords(this.name, reservedWords);
|
||||
const superTypes = distinctAndSorted(this.interfaceSuperTypes.map(e => e.name)).join(', ');
|
||||
return toString(expandToNode `
|
||||
interface ${name}${superTypes.length > 0 ? ` extends ${superTypes}` : ''} {
|
||||
${pushProperties(this.properties, 'DeclaredType')}
|
||||
}
|
||||
`.appendNewLine());
|
||||
}
|
||||
}
|
||||
export class TypeResolutionError extends Error {
|
||||
constructor(message, target) {
|
||||
super(message);
|
||||
this.name = 'TypeResolutionError';
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
export function isTypeAssignable(from, to) {
|
||||
return isTypeAssignableInternal(from, to, new Map());
|
||||
}
|
||||
function isTypeAssignableInternal(from, to, visited) {
|
||||
if (!from) {
|
||||
return true;
|
||||
}
|
||||
else if (!to) {
|
||||
return false;
|
||||
}
|
||||
const key = `${propertyTypeToKeyString(from)}»${propertyTypeToKeyString(to)}`;
|
||||
let result = visited.get(key);
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
}
|
||||
visited.set(key, false);
|
||||
result = false;
|
||||
if (isPropertyUnion(from)) {
|
||||
result = from.types.every(fromType => isTypeAssignableInternal(fromType, to, visited));
|
||||
}
|
||||
else if (isPropertyUnion(to)) {
|
||||
result = to.types.some(toType => isTypeAssignableInternal(from, toType, visited));
|
||||
}
|
||||
else if (isReferenceType(from)) {
|
||||
result = isReferenceType(to)
|
||||
&& from.isMulti === to.isMulti
|
||||
&& from.isSingle === to.isSingle
|
||||
&& isTypeAssignableInternal(from.referenceType, to.referenceType, visited);
|
||||
}
|
||||
else if (isArrayType(from)) {
|
||||
result = isArrayType(to) && isTypeAssignableInternal(from.elementType, to.elementType, visited);
|
||||
}
|
||||
else if (isValueType(from)) {
|
||||
if (isUnionType(from.value)) {
|
||||
if (from.value.dataType) {
|
||||
// We can test the primitive data type directly
|
||||
// This potentially skips a expensive recursive call
|
||||
// This also helps in case the computed internal data type does not fit the declared data type
|
||||
const primitiveType = {
|
||||
primitive: from.value.dataType
|
||||
};
|
||||
result = isTypeAssignableInternal(primitiveType, to, visited);
|
||||
}
|
||||
if (!result) {
|
||||
result = isTypeAssignableInternal(from.value.type, to, visited);
|
||||
}
|
||||
}
|
||||
else if (!isValueType(to)) {
|
||||
result = false;
|
||||
}
|
||||
else if (isUnionType(to.value)) {
|
||||
result = isTypeAssignableInternal(from, to.value.type, visited);
|
||||
}
|
||||
else {
|
||||
result = isInterfaceAssignable(from.value, to.value, new Set());
|
||||
}
|
||||
}
|
||||
else if (isValueType(to) && isUnionType(to.value)) {
|
||||
if (isValueType(from) && isUnionType(from.value) && to.value.name === from.value.name) {
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
result = isTypeAssignableInternal(from, to.value.type, visited);
|
||||
}
|
||||
}
|
||||
else if (isPrimitiveType(from)) {
|
||||
result = isPrimitiveType(to) && from.primitive === to.primitive;
|
||||
}
|
||||
else if (isStringType(from)) {
|
||||
result = (isPrimitiveType(to) && to.primitive === 'string') || (isStringType(to) && to.string === from.string);
|
||||
}
|
||||
if (result) {
|
||||
visited.set(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function isInterfaceAssignable(from, to, visited) {
|
||||
const key = from.name;
|
||||
if (visited.has(key)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
visited.add(key);
|
||||
}
|
||||
if (from.name === to.name) {
|
||||
return true;
|
||||
}
|
||||
for (const superType of from.superTypes) {
|
||||
if (isInterfaceType(superType) && isInterfaceAssignable(superType, to, visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function propertyTypeToKeyString(type) {
|
||||
if (isReferenceType(type)) {
|
||||
return `@(${propertyTypeToKeyString(type.referenceType)})${type.isMulti ? '*' : ''}`;
|
||||
}
|
||||
else if (isArrayType(type)) {
|
||||
return type.elementType ? `(${propertyTypeToKeyString(type.elementType)})[]` : 'unknown[]';
|
||||
}
|
||||
else if (isPropertyUnion(type)) {
|
||||
const union = type.types.map(e => propertyTypeToKeyString(e)).join(' | ');
|
||||
if (type.types.length <= 1) {
|
||||
return `Union<${union}>`;
|
||||
}
|
||||
return union;
|
||||
}
|
||||
else if (isValueType(type)) {
|
||||
return `Value<${type.value.name}>`;
|
||||
}
|
||||
else if (isPrimitiveType(type)) {
|
||||
return type.primitive;
|
||||
}
|
||||
else if (isStringType(type)) {
|
||||
return `'${type.string}'`;
|
||||
}
|
||||
throw new Error('Invalid type');
|
||||
}
|
||||
export function propertyTypeToString(type, mode = 'AstType') {
|
||||
if (!type) {
|
||||
return 'unknown';
|
||||
}
|
||||
if (isReferenceType(type)) {
|
||||
const refType = propertyTypeToString(type.referenceType, mode);
|
||||
return mode === 'AstType' ? `langium.${type.isMulti ? 'Multi' : ''}Reference<${refType}>` : `@${typeParenthesis(type.referenceType, refType)}${type.isMulti ? '+' : ''}`;
|
||||
}
|
||||
else if (isArrayType(type)) {
|
||||
const arrayType = propertyTypeToString(type.elementType, mode);
|
||||
return mode === 'AstType' ? `Array<${arrayType}>` : `${type.elementType ? typeParenthesis(type.elementType, arrayType) : 'unknown'}[]`;
|
||||
}
|
||||
else if (isPropertyUnion(type)) {
|
||||
const types = type.types.map(e => typeParenthesis(e, propertyTypeToString(e, mode)));
|
||||
return distinctAndSorted(types).join(' | ');
|
||||
}
|
||||
else if (isValueType(type)) {
|
||||
return type.value.name;
|
||||
}
|
||||
else if (isPrimitiveType(type)) {
|
||||
return type.primitive;
|
||||
}
|
||||
else if (isStringType(type)) {
|
||||
const delimiter = mode === 'AstType' ? "'" : '"';
|
||||
return `${delimiter}${escapeQuotes(type.string, delimiter)}${delimiter}`;
|
||||
}
|
||||
throw new Error('Invalid type');
|
||||
}
|
||||
function typeParenthesis(type, name) {
|
||||
const needsParenthesis = isPropertyUnion(type);
|
||||
if (needsParenthesis) {
|
||||
name = `(${name})`;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
function pushProperties(properties, mode) {
|
||||
function propertyToNode(property) {
|
||||
// We don't need to escape reserved words in the property name
|
||||
// The parser will be able to handle it just fine
|
||||
const name = property.name;
|
||||
const optional = property.optional && !isMandatoryPropertyType(property.type);
|
||||
const propType = propertyTypeToString(property.type, mode);
|
||||
return expandToNode `${property.comment}`
|
||||
.appendNewLineIfNotEmpty()
|
||||
.append(`${name}${optional ? '?' : ''}: ${propType};`);
|
||||
}
|
||||
return joinToNode(distinctAndSorted(properties, (a, b) => a.name.localeCompare(b.name)), propertyToNode, { appendNewLineIfNotEmpty: true });
|
||||
}
|
||||
export function isMandatoryPropertyType(propertyType) {
|
||||
if (isArrayType(propertyType)) {
|
||||
return true;
|
||||
}
|
||||
else if (isReferenceType(propertyType)) {
|
||||
return false;
|
||||
}
|
||||
else if (isPropertyUnion(propertyType)) {
|
||||
return propertyType.types.every(e => isMandatoryPropertyType(e));
|
||||
}
|
||||
else if (isPrimitiveType(propertyType)) {
|
||||
const value = propertyType.primitive;
|
||||
return value === 'boolean';
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function addReflectionInfo(name, properties = []) {
|
||||
return expandToNode `
|
||||
export const ${name} = {
|
||||
$type: '${name}'${properties.length > 0 ? ',' : ''}
|
||||
${joinToNode(properties.sort((a, b) => a.name.localeCompare(b.name)), prop => `${prop.name}: '${escapeQuotes(prop.name, "'")}'`, { separator: ',', appendNewLineIfNotEmpty: true })}
|
||||
} as const;
|
||||
|
||||
export function is${name}(item: unknown): item is ${name} {
|
||||
return reflection.isInstance(item, ${name}.$type);
|
||||
}
|
||||
`.appendNewLine();
|
||||
}
|
||||
function addDataTypeReflectionInfo(union) {
|
||||
switch (union.dataType) {
|
||||
case 'string':
|
||||
if (containsOnlyStringTypes(union.type)) {
|
||||
const subTypes = Array.from(union.subTypes).map(e => e.name);
|
||||
const strings = collectStringValuesFromDataType(union.type);
|
||||
const regexes = collectRegexesFromDataType(union.type);
|
||||
if (subTypes.length === 0 && strings.length === 0 && regexes.length === 0) {
|
||||
return generateIsDataTypeFunction(union.name, `typeof item === '${union.dataType}'`);
|
||||
}
|
||||
else {
|
||||
const returnString = createDataTypeCheckerFunctionReturnString(subTypes, strings, regexes);
|
||||
return generateIsDataTypeFunction(union.name, returnString);
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
case 'bigint':
|
||||
return generateIsDataTypeFunction(union.name, `typeof item === '${union.dataType}'`);
|
||||
case 'Date':
|
||||
return generateIsDataTypeFunction(union.name, 'item instanceof Date');
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
function containsOnlyStringTypes(propertyType) {
|
||||
let result = true;
|
||||
if (isPrimitiveType(propertyType)) {
|
||||
if (propertyType.primitive === 'string') {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (isStringType(propertyType)) {
|
||||
return true;
|
||||
}
|
||||
else if (!isPropertyUnion(propertyType)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
for (const type of propertyType.types) {
|
||||
if (isValueType(type)) {
|
||||
if (isUnionType(type.value)) {
|
||||
if (!containsOnlyStringTypes(type.value.type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (isPrimitiveType(type)) {
|
||||
if (type.primitive !== 'string' || !type.regex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (isPropertyUnion(type)) {
|
||||
result = containsOnlyStringTypes(type);
|
||||
}
|
||||
else if (!isStringType(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function createDataTypeCheckerFunctionReturnString(subTypes, strings, regexes) {
|
||||
const allArray = [
|
||||
...subTypes.map(e => `is${e}(item)`),
|
||||
...strings.map(e => `item === '${e}'`)
|
||||
];
|
||||
if (regexes.length > 0) {
|
||||
const joinedRegexes = regexes.map(e => `${e}.test(item)`).join(' || ');
|
||||
allArray.push(`(typeof item === 'string' && (${joinedRegexes}))`);
|
||||
}
|
||||
return allArray.join(' || ');
|
||||
}
|
||||
function escapeReservedWords(name, reserved) {
|
||||
return reserved.has(name) ? `^${name}` : name;
|
||||
}
|
||||
function collectStringValuesFromDataType(propertyType) {
|
||||
const values = [];
|
||||
if (isStringType(propertyType)) {
|
||||
return [propertyType.string];
|
||||
}
|
||||
if (isPropertyUnion(propertyType)) {
|
||||
for (const type of propertyType.types) {
|
||||
if (isStringType(type)) {
|
||||
values.push(type.string);
|
||||
}
|
||||
else if (isPropertyUnion(type)) {
|
||||
values.push(...collectStringValuesFromDataType(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
function collectRegexesFromDataType(propertyType) {
|
||||
const regexes = [];
|
||||
if (isPrimitiveType(propertyType) && propertyType.primitive === 'string' && propertyType.regex) {
|
||||
regexes.push(propertyType.regex);
|
||||
}
|
||||
if (isPropertyUnion(propertyType)) {
|
||||
for (const type of propertyType.types) {
|
||||
if (isPrimitiveType(type) && type.primitive === 'string' && type.regex) {
|
||||
regexes.push(type.regex);
|
||||
}
|
||||
else if (isPropertyUnion(type)) {
|
||||
regexes.push(...collectRegexesFromDataType(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
return regexes;
|
||||
}
|
||||
function generateIsDataTypeFunction(unionName, returnString) {
|
||||
return expandToNode `
|
||||
export function is${unionName}(item: unknown): item is ${unionName} {
|
||||
return ${returnString};
|
||||
}
|
||||
`.appendNewLine();
|
||||
}
|
||||
//# sourceMappingURL=types.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+34
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************
|
||||
* 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 type { References } from '../../references/references.js';
|
||||
import type { AstNodeLocator } from '../../workspace/ast-node-locator.js';
|
||||
import type { LangiumDocuments } from '../../workspace/documents.js';
|
||||
import type { Interface, Type, AbstractType } from '../../languages/generated/ast.js';
|
||||
import type { PlainInterface, PlainProperty } from './type-collector/plain-types.js';
|
||||
import type { AstTypes, InterfaceType, PropertyType, TypeOption } from './type-collector/types.js';
|
||||
import { MultiMap } from '../../utils/collections.js';
|
||||
/**
|
||||
* Collects all properties of all interface types. Includes super type properties.
|
||||
* @param interfaces A topologically sorted array of interfaces.
|
||||
*/
|
||||
export declare function collectAllPlainProperties(interfaces: PlainInterface[]): MultiMap<string, PlainProperty>;
|
||||
export declare function distinctAndSorted<T>(list: T[], compareFn?: (a: T, b: T) => number): T[];
|
||||
export declare function collectChildrenTypes(interfaceNode: Interface, references: References, langiumDocuments: LangiumDocuments, nodeLocator: AstNodeLocator): Set<Interface | Type>;
|
||||
export declare function collectTypeHierarchy(types: TypeOption[]): {
|
||||
superTypes: MultiMap<string, string>;
|
||||
subTypes: MultiMap<string, string>;
|
||||
};
|
||||
export declare function collectSuperTypes(ruleNode: AbstractType): Set<Interface>;
|
||||
export declare function mergeInterfaces(inferred: AstTypes, declared: AstTypes): InterfaceType[];
|
||||
export declare function mergeTypesAndInterfaces(astTypes: AstTypes): TypeOption[];
|
||||
export declare function hasArrayType(type: PropertyType): boolean;
|
||||
export declare function hasBooleanType(type: PropertyType): boolean;
|
||||
export declare function findReferenceTypes(type: PropertyType): string[];
|
||||
export declare function findAstTypes(type: PropertyType): string[];
|
||||
export declare function isAstType(type: PropertyType): boolean;
|
||||
export declare function isAstTypeInternal(type: PropertyType, visited: Map<PropertyType, boolean>): boolean;
|
||||
export declare function escapeQuotes(str: string, type?: '"' | "'"): string;
|
||||
//# sourceMappingURL=types-util.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types-util.d.ts","sourceRoot":"","sources":["../../../src/grammar/type-system/types-util.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAkB,MAAM,kCAAkC,CAAC;AACtG,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrF,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAItD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,CAcvG;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,GAAG,CAAC,EAAE,CAEvF;AAED,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,GAAG,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAmB7K;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG;IACvD,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC,CA+BA;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,GAAG,CAAC,SAAS,CAAC,CAuBxE;AAcD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,aAAa,EAAE,CAEvF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,EAAE,CAExE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAQxD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAQ1D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAY/D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAEzD;AAuBD,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAErD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,OAAO,CAyBlG;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,GAAG,GAAG,GAAS,GAAG,MAAM,CAMvE"}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
/******************************************************************************
|
||||
* 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 { MultiMap } from '../../utils/collections.js';
|
||||
import { isInterface, isType, isUnionType, isSimpleType } from '../../languages/generated/ast.js';
|
||||
import { isArrayType, isPrimitiveType, isPropertyUnion, isReferenceType, isValueType } from './type-collector/types.js';
|
||||
/**
|
||||
* Collects all properties of all interface types. Includes super type properties.
|
||||
* @param interfaces A topologically sorted array of interfaces.
|
||||
*/
|
||||
export function collectAllPlainProperties(interfaces) {
|
||||
const map = new MultiMap();
|
||||
for (const interfaceType of interfaces) {
|
||||
map.addAll(interfaceType.name, interfaceType.properties);
|
||||
}
|
||||
for (const interfaceType of interfaces) {
|
||||
for (const superType of interfaceType.superTypes) {
|
||||
const superTypeProperties = map.get(superType);
|
||||
if (superTypeProperties) {
|
||||
map.addAll(interfaceType.name, superTypeProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
export function distinctAndSorted(list, compareFn) {
|
||||
return Array.from(new Set(list)).sort(compareFn);
|
||||
}
|
||||
export function collectChildrenTypes(interfaceNode, references, langiumDocuments, nodeLocator) {
|
||||
const childrenTypes = new Set();
|
||||
childrenTypes.add(interfaceNode);
|
||||
const refs = references.findReferences(interfaceNode, {});
|
||||
for (const ref of refs) {
|
||||
const doc = langiumDocuments.getDocument(ref.sourceUri);
|
||||
if (!doc) {
|
||||
continue;
|
||||
}
|
||||
const astNode = nodeLocator.getAstNode(doc.parseResult.value, ref.sourcePath);
|
||||
if (isInterface(astNode)) {
|
||||
childrenTypes.add(astNode);
|
||||
const childrenOfInterface = collectChildrenTypes(astNode, references, langiumDocuments, nodeLocator);
|
||||
childrenOfInterface.forEach(child => childrenTypes.add(child));
|
||||
}
|
||||
else if (astNode && isType(astNode.$container)) {
|
||||
childrenTypes.add(astNode.$container);
|
||||
}
|
||||
}
|
||||
return childrenTypes;
|
||||
}
|
||||
export function collectTypeHierarchy(types) {
|
||||
const allTypes = new Set(types);
|
||||
const duplicateSuperTypes = new MultiMap();
|
||||
const duplicateSubTypes = new MultiMap();
|
||||
for (const type of allTypes) {
|
||||
for (const superType of type.superTypes) {
|
||||
if (allTypes.has(superType)) {
|
||||
duplicateSuperTypes.add(type.name, superType.name);
|
||||
duplicateSubTypes.add(superType.name, type.name);
|
||||
}
|
||||
}
|
||||
for (const subType of type.subTypes) {
|
||||
if (allTypes.has(subType)) {
|
||||
duplicateSuperTypes.add(subType.name, type.name);
|
||||
duplicateSubTypes.add(type.name, subType.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
const superTypes = new MultiMap();
|
||||
const subTypes = new MultiMap();
|
||||
// Deduplicate and sort
|
||||
for (const [name, superTypeList] of Array.from(duplicateSuperTypes.entriesGroupedByKey()).sort(([aName], [bName]) => aName.localeCompare(bName))) {
|
||||
superTypes.addAll(name, Array.from(new Set(superTypeList)));
|
||||
}
|
||||
for (const [name, subTypeList] of Array.from(duplicateSubTypes.entriesGroupedByKey()).sort(([aName], [bName]) => aName.localeCompare(bName))) {
|
||||
subTypes.addAll(name, Array.from(new Set(subTypeList)));
|
||||
}
|
||||
return {
|
||||
superTypes,
|
||||
subTypes
|
||||
};
|
||||
}
|
||||
export function collectSuperTypes(ruleNode) {
|
||||
const superTypes = new Set();
|
||||
if (isInterface(ruleNode)) {
|
||||
superTypes.add(ruleNode);
|
||||
ruleNode.superTypes.forEach(superType => {
|
||||
if (isInterface(superType.ref)) {
|
||||
superTypes.add(superType.ref);
|
||||
const collectedSuperTypes = collectSuperTypes(superType.ref);
|
||||
for (const superType of collectedSuperTypes) {
|
||||
superTypes.add(superType);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (isType(ruleNode)) {
|
||||
const usedTypes = collectUsedTypes(ruleNode.type);
|
||||
for (const usedType of usedTypes) {
|
||||
const collectedSuperTypes = collectSuperTypes(usedType);
|
||||
for (const superType of collectedSuperTypes) {
|
||||
superTypes.add(superType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return superTypes;
|
||||
}
|
||||
function collectUsedTypes(typeDefinition) {
|
||||
if (isUnionType(typeDefinition)) {
|
||||
return typeDefinition.types.flatMap(e => collectUsedTypes(e));
|
||||
}
|
||||
else if (isSimpleType(typeDefinition)) {
|
||||
const value = typeDefinition.typeRef?.ref;
|
||||
if (isType(value) || isInterface(value)) {
|
||||
return [value];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
export function mergeInterfaces(inferred, declared) {
|
||||
return inferred.interfaces.concat(declared.interfaces);
|
||||
}
|
||||
export function mergeTypesAndInterfaces(astTypes) {
|
||||
return astTypes.interfaces.concat(astTypes.unions);
|
||||
}
|
||||
export function hasArrayType(type) {
|
||||
if (isPropertyUnion(type)) {
|
||||
return type.types.some(e => hasArrayType(e));
|
||||
}
|
||||
else if (isArrayType(type)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function hasBooleanType(type) {
|
||||
if (isPropertyUnion(type)) {
|
||||
return type.types.some(e => hasBooleanType(e));
|
||||
}
|
||||
else if (isPrimitiveType(type)) {
|
||||
return type.primitive === 'boolean';
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function findReferenceTypes(type) {
|
||||
if (isPropertyUnion(type)) {
|
||||
return type.types.flatMap(e => findReferenceTypes(e));
|
||||
}
|
||||
else if (isReferenceType(type)) {
|
||||
const refType = type.referenceType;
|
||||
if (isValueType(refType)) {
|
||||
return [refType.value.name];
|
||||
}
|
||||
}
|
||||
else if (isArrayType(type)) {
|
||||
return type.elementType ? findReferenceTypes(type.elementType) : [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
export function findAstTypes(type) {
|
||||
return findAstTypesInternal(type, new Set());
|
||||
}
|
||||
function findAstTypesInternal(type, visited) {
|
||||
if (visited.has(type)) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
visited.add(type);
|
||||
}
|
||||
if (isPropertyUnion(type)) {
|
||||
return type.types.flatMap(e => findAstTypesInternal(e, visited));
|
||||
}
|
||||
else if (isValueType(type)) {
|
||||
const value = type.value;
|
||||
if ('type' in value) {
|
||||
return findAstTypesInternal(value.type, visited);
|
||||
}
|
||||
else {
|
||||
return [value.name];
|
||||
}
|
||||
}
|
||||
else if (isArrayType(type)) {
|
||||
return type.elementType ? findAstTypesInternal(type.elementType, visited) : [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
export function isAstType(type) {
|
||||
return isAstTypeInternal(type, new Map());
|
||||
}
|
||||
export function isAstTypeInternal(type, visited) {
|
||||
if (visited.has(type)) {
|
||||
return visited.get(type);
|
||||
}
|
||||
// This is supposed to prevent infinite recursion.
|
||||
// Setting this to true is a pretty safe assumption.
|
||||
// Setting it to false might lead to false negatives for property unions.
|
||||
visited.set(type, true);
|
||||
let result = false;
|
||||
if (isPropertyUnion(type)) {
|
||||
result = type.types.every(e => isAstTypeInternal(e, visited));
|
||||
}
|
||||
else if (isValueType(type)) {
|
||||
const value = type.value;
|
||||
if ('type' in value) {
|
||||
result = isAstTypeInternal(value.type, visited);
|
||||
}
|
||||
else {
|
||||
// Is definitely an interface type
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
visited.set(type, result);
|
||||
return result;
|
||||
}
|
||||
export function escapeQuotes(str, type = '"') {
|
||||
if (type === '"') {
|
||||
return str.replace(/"/g, '\\"');
|
||||
}
|
||||
else {
|
||||
return str.replace(/'/g, "\\'");
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=types-util.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user