@abaplint/core
Version:
abaplint - Core API
358 lines • 12.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Registry = void 0;
const config_1 = require("./config");
const artifacts_objects_1 = require("./artifacts_objects");
const find_global_definitions_1 = require("./abap/5_syntax/global_definitions/find_global_definitions");
const excludeHelper_1 = require("./utils/excludeHelper");
const ddic_references_1 = require("./ddic_references");
const rules_runner_1 = require("./rules_runner");
const msag_references_1 = require("./msag_references");
const macro_references_1 = require("./macro_references");
// todo, this should really be an instance in case there are multiple Registry'ies
class ParsingPerformance {
static clear() {
this.results = [];
this.lexing = 0;
this.statements = 0;
this.structure = 0;
}
static push(obj, result) {
if (result.runtimeExtra) {
this.lexing += result.runtimeExtra.lexing;
this.statements += result.runtimeExtra.statements;
this.structure += result.runtimeExtra.structure;
}
if (result.runtime < 100) {
return;
}
if (this.results === undefined) {
this.results = [];
}
let extra = "";
if (result.runtimeExtra) {
extra = `\t(lexing: ${result.runtimeExtra.lexing}ms, statements: ${result.runtimeExtra.statements}ms, structure: ${result.runtimeExtra.structure}ms)`;
}
this.results.push({
runtime: result.runtime,
extra,
name: obj.getType() + " " + obj.getName(),
});
}
static output() {
const MAX = 10;
this.results.sort((a, b) => { return b.runtime - a.runtime; });
for (let i = 0; i < MAX; i++) {
const row = this.results[i];
if (row === undefined) {
break;
}
process.stderr.write(`\t${row.runtime}ms\t${row.name} ${row.extra}\n`);
}
process.stderr.write(`\tTotal lexing: ${this.lexing}ms\n`);
process.stderr.write(`\tTotal statements: ${this.statements}ms\n`);
process.stderr.write(`\tTotal structure: ${this.structure}ms\n`);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
class Registry {
constructor(conf) {
this.objects = {};
this.objectsByType = {};
this.dependencies = {};
this.setConfig(conf ? conf : config_1.Config.getDefault());
this.ddicReferences = new ddic_references_1.DDICReferences();
this.msagReferences = new msag_references_1.MSAGReferences();
this.macroReferences = new macro_references_1.MacroReferences();
}
static abaplintVersion() {
// magic, see build script "version.sh"
return "2.113.186";
}
getDDICReferences() {
return this.ddicReferences;
}
getMSAGReferences() {
return this.msagReferences;
}
getMacroReferences() {
return this.macroReferences;
}
*getObjects() {
for (const name in this.objects) {
for (const type in this.objects[name]) {
yield this.objects[name][type];
}
}
}
*getObjectsByType(type) {
for (const name in this.objectsByType[type] || []) {
yield this.objectsByType[type][name];
}
}
*getFiles() {
for (const obj of this.getObjects()) {
for (const file of obj.getFiles()) {
yield file;
}
}
}
getFirstObject() {
for (const name in this.objects) {
for (const type in this.objects[name]) {
return this.objects[name][type];
}
}
return undefined;
}
getObjectCount(skipDependencies = true) {
let res = 0;
for (const o of this.getObjects()) {
if (skipDependencies === true && this.isDependency(o)) {
continue;
}
res = res + 1;
}
return res;
}
getFileByName(filename) {
const upper = filename.toUpperCase();
for (const o of this.getObjects()) {
for (const f of o.getFiles()) {
if (f.getFilename().toUpperCase() === upper) {
return f;
}
}
}
return undefined;
}
getObject(type, name) {
if (type === undefined || name === undefined) {
return undefined;
}
const searchName = name.toUpperCase();
if (this.objects[searchName]) {
return this.objects[searchName][type];
}
return undefined;
}
getConfig() {
return this.conf;
}
// assumption: Config is immutable, and can only be changed via this method
setConfig(conf) {
for (const obj of this.getObjects()) {
obj.setDirty();
}
this.conf = conf;
this.errorNamespace = new RegExp(this.getConfig().getSyntaxSetttings().errorNamespace, "i");
return this;
}
inErrorNamespace(name) {
return this.errorNamespace.test(name);
}
addFile(file) {
return this.addFiles([file]);
}
updateFile(file) {
const obj = this.find(file.getObjectName(), file.getObjectType());
obj.updateFile(file);
return this;
}
removeFile(file) {
const obj = this.find(file.getObjectName(), file.getObjectType());
obj.removeFile(file);
if (obj.getFiles().length === 0) {
this.ddicReferences.clear(obj);
this.msagReferences.clear(obj);
this.removeObject(obj);
}
return this;
}
_addFiles(files, dependency) {
var _a;
const globalExclude = ((_a = this.conf.getGlobal().exclude) !== null && _a !== void 0 ? _a : [])
.map(pattern => new RegExp(pattern, "i"));
for (const f of files) {
const filename = f.getFilename();
const isNotAbapgitFile = filename.split(".").length <= 2;
if (isNotAbapgitFile || excludeHelper_1.ExcludeHelper.isExcluded(filename, globalExclude)) {
continue;
}
let found = this.findOrCreate(f.getObjectName(), f.getObjectType());
if (dependency === false && found && this.isDependency(found)) {
this.removeDependency(found);
found = this.findOrCreate(f.getObjectName(), f.getObjectType());
}
found.addFile(f);
}
return this;
}
addFiles(files) {
this._addFiles(files, false);
return this;
}
addDependencies(files) {
for (const f of files) {
this.addDependency(f);
}
return this;
}
addDependency(file) {
var _a;
const type = (_a = file.getObjectType()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
if (type === undefined) {
return this;
}
const name = file.getObjectName().toUpperCase();
if (this.dependencies[type] === undefined) {
this.dependencies[type] = {};
}
this.dependencies[type][name] = true;
this._addFiles([file], true);
return this;
}
removeDependency(obj) {
var _a;
(_a = this.dependencies[obj.getType()]) === null || _a === void 0 ? true : delete _a[obj.getName()];
this.removeObject(obj);
}
isDependency(obj) {
var _a;
return ((_a = this.dependencies[obj.getType()]) === null || _a === void 0 ? void 0 : _a[obj.getName()]) === true;
}
isFileDependency(filename) {
var _a, _b;
const f = this.getFileByName(filename);
if (f === undefined) {
return false;
}
const type = (_a = f.getObjectType()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
if (type === undefined) {
return false;
}
const name = f.getObjectName().toUpperCase();
return ((_b = this.dependencies[type]) === null || _b === void 0 ? void 0 : _b[name]) === true;
}
// assumption: the file is already in the registry
findObjectForFile(file) {
const filename = file.getFilename();
for (const obj of this.getObjects()) {
for (const ofile of obj.getFiles()) {
if (ofile.getFilename() === filename) {
return obj;
}
}
}
return undefined;
}
// todo, this will be changed to async sometime
findIssues(input) {
if (this.isDirty() === true) {
this.parse();
}
return new rules_runner_1.RulesRunner(this).runRules(this.getObjects(), input);
}
// todo, this will be changed to async sometime
findIssuesObject(iobj) {
if (this.isDirty() === true) {
this.parse();
}
return new rules_runner_1.RulesRunner(this).runRules([iobj]);
}
// todo, this will be changed to async sometime
parse() {
if (this.isDirty() === false) {
return this;
}
ParsingPerformance.clear();
for (const o of this.getObjects()) {
this.parsePrivate(o);
}
new find_global_definitions_1.FindGlobalDefinitions(this).run();
return this;
}
async parseAsync(input) {
var _a, _b;
if (this.isDirty() === false) {
return this;
}
ParsingPerformance.clear();
(_a = input === null || input === void 0 ? void 0 : input.progress) === null || _a === void 0 ? void 0 : _a.set(this.getObjectCount(false), "Lexing and parsing");
for (const o of this.getObjects()) {
await ((_b = input === null || input === void 0 ? void 0 : input.progress) === null || _b === void 0 ? void 0 : _b.tick("Lexing and parsing(" + this.conf.getVersion() + ") - " + o.getType() + " " + o.getName()));
this.parsePrivate(o);
}
if ((input === null || input === void 0 ? void 0 : input.outputPerformance) === true) {
ParsingPerformance.output();
}
new find_global_definitions_1.FindGlobalDefinitions(this).run(input === null || input === void 0 ? void 0 : input.progress);
return this;
}
//////////////////////////////////////////
// todo, refactor, this is a mess, see where-used, a lot of the code should be in this method instead
parsePrivate(input) {
const config = this.getConfig();
const result = input.parse(config.getVersion(), config.getSyntaxSetttings().globalMacros, this);
ParsingPerformance.push(input, result);
}
isDirty() {
for (const o of this.getObjects()) {
const dirty = o.isDirty();
if (dirty === true) {
return true;
}
}
return false;
}
findOrCreate(name, type) {
try {
return this.find(name, type);
}
catch (_a) {
const newName = name.toUpperCase();
const newType = type ? type : "UNKNOWN";
const add = artifacts_objects_1.ArtifactsObjects.newObject(newName, newType);
if (this.objects[newName] === undefined) {
this.objects[newName] = {};
}
this.objects[newName][newType] = add;
if (this.objectsByType[newType] === undefined) {
this.objectsByType[newType] = {};
}
this.objectsByType[newType][newName] = add;
return add;
}
}
removeObject(remove) {
if (remove === undefined) {
return;
}
if (this.objects[remove.getName()][remove.getType()] === undefined) {
throw new Error("removeObject: object not found");
}
if (Object.keys(this.objects[remove.getName()]).length === 1) {
delete this.objects[remove.getName()];
}
else {
delete this.objects[remove.getName()][remove.getType()];
}
if (Object.keys(this.objectsByType[remove.getType()]).length === 1) {
delete this.objectsByType[remove.getType()];
}
else {
delete this.objectsByType[remove.getType()][remove.getName()];
}
}
find(name, type) {
const searchType = type ? type : "UNKNOWN";
const searchName = name.toUpperCase();
if (this.objects[searchName] !== undefined
&& this.objects[searchName][searchType]) {
return this.objects[searchName][searchType];
}
throw new Error("find: object not found, " + type + " " + name);
}
}
exports.Registry = Registry;
//# sourceMappingURL=registry.js.map