93 lines
4.1 KiB
JavaScript
93 lines
4.1 KiB
JavaScript
/******************************************************************************
|
|
* 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 { stream } from '../../utils/stream.js';
|
|
import { isAction, isAlternatives, isGroup, isUnorderedGroup } from '../../languages/generated/ast.js';
|
|
import { mergeInterfaces, mergeTypesAndInterfaces } from '../type-system/types-util.js';
|
|
import { collectValidationAst } from '../type-system/ast-collector.js';
|
|
import { getActionType, getRuleTypeName } from '../../utils/grammar-utils.js';
|
|
export class LangiumGrammarValidationResourcesCollector {
|
|
constructor(services) {
|
|
this.documents = services.shared.workspace.LangiumDocuments;
|
|
}
|
|
collectValidationResources(grammar) {
|
|
try {
|
|
const typeResources = collectValidationAst(grammar, this.documents);
|
|
return {
|
|
typeToValidationInfo: this.collectValidationInfo(typeResources),
|
|
typeToSuperProperties: this.collectSuperProperties(typeResources),
|
|
};
|
|
}
|
|
catch (err) {
|
|
console.error('Error collecting validation resources', err);
|
|
return { typeToValidationInfo: new Map(), typeToSuperProperties: new Map() };
|
|
}
|
|
}
|
|
collectValidationInfo({ astResources, inferred, declared }) {
|
|
const res = new Map();
|
|
const typeNameToRulesActions = collectNameToRulesActions(astResources);
|
|
for (const type of mergeTypesAndInterfaces(inferred)) {
|
|
res.set(type.name, { inferred: type, inferredNodes: typeNameToRulesActions.get(type.name) });
|
|
}
|
|
const typeNametoInterfacesUnions = stream(astResources.interfaces)
|
|
.concat(astResources.types)
|
|
.reduce((acc, type) => acc.set(type.name, type), new Map());
|
|
for (const type of mergeTypesAndInterfaces(declared)) {
|
|
const node = typeNametoInterfacesUnions.get(type.name);
|
|
if (node) {
|
|
const inferred = res.get(type.name);
|
|
res.set(type.name, Object.assign(Object.assign({}, inferred !== null && inferred !== void 0 ? inferred : {}), { declared: type, declaredNode: node }));
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
collectSuperProperties({ inferred, declared }) {
|
|
const typeToSuperProperties = new Map();
|
|
const interfaces = mergeInterfaces(inferred, declared);
|
|
const interfaceMap = new Map(interfaces.map(e => [e.name, e]));
|
|
for (const type of mergeInterfaces(inferred, declared)) {
|
|
typeToSuperProperties.set(type.name, this.addSuperProperties(type, interfaceMap, new Set()));
|
|
}
|
|
return typeToSuperProperties;
|
|
}
|
|
addSuperProperties(interfaceType, map, visited) {
|
|
if (visited.has(interfaceType.name)) {
|
|
return [];
|
|
}
|
|
visited.add(interfaceType.name);
|
|
const properties = [...interfaceType.properties];
|
|
for (const superType of interfaceType.superTypes) {
|
|
const value = map.get(superType.name);
|
|
if (value) {
|
|
properties.push(...this.addSuperProperties(value, map, visited));
|
|
}
|
|
}
|
|
return properties;
|
|
}
|
|
}
|
|
function collectNameToRulesActions({ parserRules, datatypeRules }) {
|
|
const acc = new MultiMap();
|
|
// collect rules
|
|
stream(parserRules)
|
|
.concat(datatypeRules)
|
|
.forEach(rule => acc.add(getRuleTypeName(rule), rule));
|
|
// collect actions
|
|
function collectActions(element) {
|
|
if (isAction(element)) {
|
|
const name = getActionType(element);
|
|
if (name) {
|
|
acc.add(name, element);
|
|
}
|
|
}
|
|
if (isAlternatives(element) || isGroup(element) || isUnorderedGroup(element)) {
|
|
element.elements.forEach(e => collectActions(e));
|
|
}
|
|
}
|
|
parserRules
|
|
.forEach(rule => collectActions(rule.definition));
|
|
return acc;
|
|
}
|
|
//# sourceMappingURL=validation-resources-collector.js.map
|