@jqassistant/ts-lce
Version:
Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.
138 lines (137 loc) • 4.76 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LCENamedConcept = exports.LCEConcept = void 0;
exports.isNamedConcept = isNamedConcept;
exports.mergeConceptMaps = mergeConceptMaps;
exports.unifyConceptMap = unifyConceptMap;
exports.singleEntryConceptMap = singleEntryConceptMap;
exports.createConceptMap = createConceptMap;
exports.getAndCastConcepts = getAndCastConcepts;
const context_1 = require("./context");
/**
* Base class for all language concepts.
*/
class LCEConcept {
/**
* Unique identifier for a concept class.
* Should be set by subclasses.
*/
static conceptId;
/**
* Contains metadata that may be used by Processors further up the AST, or by Post-Processors.
* NOTE: metadata should not be used in the toJSON method, as Concept classes should not contain any processing logic.
*/
metadata = new Map();
/**
* Returns a JSON object that contains all the information that should be present in the JSON report that is used for graph generation.
* NOTE: This method should not contain any processing logic!
*
* Returns all fields, except metadata by default. Also calls toJSON for all fields that are concepts, or concept arrays.
*/
toJSON() {
const jsonObject = {};
Object.entries(this).forEach(([key, value]) => {
if (value instanceof LCEConcept) {
jsonObject[key] = value.toJSON();
}
else if (Array.isArray(value) && value.every(item => item instanceof LCEConcept)) {
jsonObject[key] = value.map(item => item.toJSON());
}
else if (key === "fqn" && value instanceof context_1.FQN) {
jsonObject["globalFqn"] = value.globalFqn;
jsonObject["localFqn"] = value.localFqn;
}
else if (key !== 'metadata') {
jsonObject[key] = value;
}
});
return jsonObject;
}
;
}
exports.LCEConcept = LCEConcept;
/**
* Base class for all language concepts that can be referred to by a fully qualified name.
*/
class LCENamedConcept extends LCEConcept {
fqn;
constructor(fqn) {
super();
this.fqn = fqn;
}
}
exports.LCENamedConcept = LCENamedConcept;
function isNamedConcept(concept) {
return "globalFqn" in concept && "localFqn" in concept;
}
/**
* Merges the given ConceptMaps. Array values of the same keys are concatenated.
* The original maps are not modified.
*/
function mergeConceptMaps(...maps) {
const result = new Map();
for (const map of maps) {
for (const [kO, vMap] of map.entries()) {
const outerRes = result.get(kO);
if (!outerRes) {
result.set(kO, new Map(vMap));
continue;
}
for (const [kI, vArr] of vMap.entries()) {
const innerRes = outerRes.get(kI);
if (innerRes) {
outerRes.set(kI, innerRes.concat(vArr));
}
else {
outerRes.set(kI, [...vArr]);
}
}
}
}
return result;
}
/**
* Takes all concepts and their conceptIds and unifies them under a single outer common key.
* The original map is not modified.
* @returns a new ConceptMap with a single key which maps to all concepts contained in the original map
*/
function unifyConceptMap(conceptMap, commonKey) {
const result = new Map();
let innerMap = undefined;
for (const [, vMap] of conceptMap.entries()) {
if (innerMap) {
for (const [kI, vArr] of vMap.entries()) {
const innerRes = innerMap.get(kI);
if (innerRes) {
innerMap.set(kI, innerRes.concat(vArr));
}
else {
innerMap.set(kI, [...vArr]);
}
}
}
else {
innerMap = new Map(vMap);
result.set(commonKey, innerMap);
}
}
return result;
}
/**
* creates a ConceptMap containing a single concept
*/
function singleEntryConceptMap(conceptId, concept, parentPropName = "") {
return createConceptMap(conceptId, [concept], parentPropName);
}
/**
* creates a ConceptMap containing a list of concepts of one concept type for a single parent property
*/
function createConceptMap(conceptId, concepts, parentPropName = "") {
return new Map([[parentPropName, new Map([[conceptId, concepts]])]]);
}
/**
* retrieves an array of concepts from a ConceptMap entry and casts it to the provided type
*/
function getAndCastConcepts(conceptId, concepts) {
return concepts.has(conceptId) ? concepts.get(conceptId) : [];
}