@hpcc-js/comms
Version:
hpcc-js - Communications
463 lines • 18.3 kB
JavaScript
import { __extends, __spreadArray } from "tslib";
import * as fs from "fs";
import * as path from "path";
import { Dictionary, DictionaryNoCase, find, SAXStackParser, scopedLogger, XMLNode } from "@hpcc-js/util";
import { locateClientTools } from "./eclcc";
var logger = scopedLogger("clienttools/eclmeta");
var _inspect = false;
function inspect(obj, _id, known) {
if (_inspect) {
for (var key in obj) {
var id = "".concat(_id, ".").concat(key);
if (key !== "$" && known[key] === undefined && known[key.toLowerCase() + "s"] === undefined) {
logger.debug(id);
}
}
if (obj.$) {
inspect(obj.$, _id + ".$", known);
}
}
}
var Attr = /** @class */ (function () {
function Attr(xmlAttr) {
this.__attrs = xmlAttr.$;
this.name = xmlAttr.$.name;
}
return Attr;
}());
export { Attr };
var Field = /** @class */ (function () {
function Field(definition, xmlField) {
this.__attrs = xmlField.$;
this.definition = definition;
this.name = xmlField.$.name;
this.type = xmlField.$.type;
}
Object.defineProperty(Field.prototype, "scope", {
get: function () {
return this.definition;
},
enumerable: false,
configurable: true
});
return Field;
}());
export { Field };
var ECLScope = /** @class */ (function () {
function ECLScope(name, type, sourcePath, xmlDefinitions, line, start, body, end) {
if (line === void 0) { line = 1; }
if (start === void 0) { start = 0; }
if (body === void 0) { body = 0; }
if (end === void 0) { end = Number.MAX_VALUE; }
this.name = name;
this.type = type;
this.sourcePath = path.normalize(sourcePath);
this.line = +line - 1;
this.start = +start;
this.body = +body;
this.end = +end;
this.definitions = this.parseDefinitions(xmlDefinitions);
}
Object.defineProperty(ECLScope.prototype, "scope", {
get: function () {
return this;
},
enumerable: false,
configurable: true
});
ECLScope.prototype.parseDefinitions = function (definitions) {
var _this = this;
if (definitions === void 0) { definitions = []; }
return definitions.map(function (definition) {
var retVal = new Definition(_this.sourcePath, definition);
inspect(definition, "definition", retVal);
return retVal;
});
};
ECLScope.prototype.contains = function (charOffset) {
return charOffset >= this.start && charOffset <= this.end;
};
ECLScope.prototype.scopeStackAt = function (charOffset) {
var retVal = [];
if (this.contains(charOffset)) {
retVal.push(this);
this.definitions.forEach(function (def) {
retVal = def.scopeStackAt(charOffset).concat(retVal);
});
}
return retVal;
};
ECLScope.prototype._resolve = function (defs, qualifiedID) {
if (defs === void 0) { defs = []; }
var qualifiedIDParts = qualifiedID.split(".");
var base = qualifiedIDParts.shift();
var retVal = find(defs, function (def) {
if (typeof def.name === "string" && typeof base === "string" && def.name.toLowerCase() === base.toLowerCase()) {
return true;
}
return false;
});
if (retVal && retVal.definitions.length && qualifiedIDParts.length) {
return this._resolve(retVal.definitions, qualifiedIDParts.join("."));
}
return retVal;
};
ECLScope.prototype.resolve = function (qualifiedID) {
return this._resolve(this.definitions, qualifiedID);
};
ECLScope.prototype.suggestions = function () {
var _this = this;
return this.definitions.map(function (def) {
return {
name: def.name,
type: _this.type
};
});
};
return ECLScope;
}());
export { ECLScope };
var Definition = /** @class */ (function (_super) {
__extends(Definition, _super);
function Definition(sourcePath, xmlDefinition) {
var _this = _super.call(this, xmlDefinition.$.name, xmlDefinition.$.type, sourcePath, xmlDefinition.children("Definition"), xmlDefinition.$.line, xmlDefinition.$.start, xmlDefinition.$.body, xmlDefinition.$.end) || this;
_this.__attrs = xmlDefinition.$;
_this.exported = !!xmlDefinition.$.exported;
_this.shared = !!xmlDefinition.$.shared;
_this.fullname = xmlDefinition.$.fullname;
_this.inherittype = xmlDefinition.$.inherittype;
_this.attrs = _this.parseAttrs(xmlDefinition.children("Attr"));
_this.fields = _this.parseFields(xmlDefinition.children("Field"));
return _this;
}
Definition.prototype.parseAttrs = function (attrs) {
if (attrs === void 0) { attrs = []; }
return attrs.map(function (attr) {
var retVal = new Attr(attr);
inspect(attr, "attr", retVal);
return retVal;
});
};
Definition.prototype.parseFields = function (fields) {
var _this = this;
if (fields === void 0) { fields = []; }
return fields.map(function (field) {
var retVal = new Field(_this, field);
inspect(field, "field", retVal);
return retVal;
});
};
Definition.prototype.suggestions = function () {
return _super.prototype.suggestions.call(this).concat(this.fields.map(function (field) {
return {
name: field.name,
type: field.type
};
}));
};
return Definition;
}(ECLScope));
export { Definition };
var Import = /** @class */ (function () {
function Import(xmlImport) {
this.__attrs = xmlImport.$;
this.name = xmlImport.$.name;
this.ref = xmlImport.$.ref;
this.start = xmlImport.$.start;
this.end = xmlImport.$.end;
this.line = xmlImport.$.line;
}
return Import;
}());
export { Import };
var Source = /** @class */ (function (_super) {
__extends(Source, _super);
function Source(xmlSource) {
var _this = _super.call(this, xmlSource.$.name, "source", xmlSource.$.sourcePath, xmlSource.children("Definition")) || this;
_this.__attrs = xmlSource.$;
var nameParts = xmlSource.$.name.split(".");
nameParts.pop();
var fakeNode = new XMLNode("");
fakeNode.appendAttribute("name", "$");
fakeNode.appendAttribute("ref", nameParts.join("."));
_this.imports = __spreadArray([
new Import(fakeNode)
], _this.parseImports(xmlSource.children("Import")), true);
return _this;
}
Source.prototype.parseImports = function (imports) {
if (imports === void 0) { imports = []; }
return imports.map(function (imp) {
var retVal = new Import(imp);
inspect(imp, "import", retVal);
return retVal;
});
};
Source.prototype.resolve = function (qualifiedID, charOffset) {
var retVal;
// Check Inner Scopes ---
if (!retVal && charOffset !== undefined) {
var scopes = this.scopeStackAt(charOffset);
scopes.some(function (scope) {
retVal = scope.resolve(qualifiedID);
return !!retVal;
});
}
// Check Definitions ---
if (!retVal) {
retVal = _super.prototype.resolve.call(this, qualifiedID);
}
return retVal;
};
return Source;
}(ECLScope));
export { Source };
var isHiddenDirectory = function (source) { return path.basename(source).indexOf(".") === 0; };
var isDirectory = function (source) { return fs.lstatSync(source).isDirectory() && !isHiddenDirectory(source); };
var isEcl = function (source) { return [".ecl", ".ecllib"].indexOf(path.extname(source).toLowerCase()) >= 0; };
var modAttrs = function (source) { return fs.readdirSync(source).map(function (name) { return path.join(source, name); }).filter(function (path) { return isDirectory(path) || isEcl(path); }); };
var File = /** @class */ (function (_super) {
__extends(File, _super);
function File(name, sourcePath) {
return _super.call(this, name, "file", sourcePath, []) || this;
}
File.prototype.suggestions = function () {
return [];
};
return File;
}(ECLScope));
export { File };
var Folder = /** @class */ (function (_super) {
__extends(Folder, _super);
function Folder(name, sourcePath) {
return _super.call(this, name, "folder", sourcePath, []) || this;
}
Folder.prototype.suggestions = function () {
return modAttrs(this.sourcePath).map(function (folder) {
return {
name: path.basename(folder, ".ecl"),
type: "folder"
};
});
};
return Folder;
}(ECLScope));
export { Folder };
var Workspace = /** @class */ (function () {
function Workspace(workspacePath, eclccPath) {
this._sourceByID = new DictionaryNoCase();
this._sourceByPath = new Dictionary();
this._test = new DictionaryNoCase();
this._workspacePath = workspacePath;
this._eclccPath = eclccPath;
}
Workspace.prototype.refresh = function () {
this.primeWorkspace();
this.primeClientTools();
};
Workspace.prototype.primeClientTools = function () {
var _this = this;
return locateClientTools(this._eclccPath, "", this._workspacePath).then(function (clientTools) {
_this._clientTools = clientTools;
return clientTools.paths();
}).then(function (paths) {
for (var _i = 0, _a = ["ECLCC_ECLLIBRARY_PATH", "ECLCC_PLUGIN_PATH"]; _i < _a.length; _i++) {
var knownFolder = _a[_i];
if (paths[knownFolder] && fs.existsSync(paths[knownFolder])) {
_this.walkChildFolders(paths[knownFolder], paths[knownFolder]);
}
}
return _this;
});
};
Workspace.prototype.primeWorkspace = function () {
if (fs.existsSync(this._workspacePath)) {
this.visitFolder(this._workspacePath, this._workspacePath);
}
};
Workspace.prototype.walkChildFolders = function (folderPath, refPath, force) {
if (force === void 0) { force = false; }
for (var _i = 0, _a = modAttrs(folderPath); _i < _a.length; _i++) {
var child = _a[_i];
if (!isDirectory(child)) {
this.visitFile(child, refPath, force);
}
else {
this.visitFolder(child, refPath, force);
}
}
};
Workspace.prototype.visitFile = function (filePath, refPath, force) {
if (force === void 0) { force = false; }
var filePathInfo = path.parse(filePath);
var pathNoExt = path.join(filePathInfo.dir, filePathInfo.name);
var name = path.relative(refPath, pathNoExt).split(path.sep).join(".");
if (force || !this._test.has(name)) {
this._test.set(name, new File("", filePath));
}
};
Workspace.prototype.visitFolder = function (folderPath, refPath, force) {
if (force === void 0) { force = false; }
var name = path.relative(refPath, folderPath).split(path.sep).join(".");
if (force || !this._test.has(name)) {
this._test.set(name, new Folder(name, folderPath));
this.walkChildFolders(folderPath, refPath, force);
}
};
Workspace.prototype.buildStack = function (parentStack, name, removeDupID) {
var nameStack = name.split(".");
if (removeDupID && parentStack[parentStack.length - 1] === nameStack[0]) {
nameStack.shift();
}
var stack = __spreadArray(__spreadArray([], parentStack, true), nameStack, true);
var qid = stack.join(".");
return {
stack: stack,
qid: qid
};
};
Workspace.prototype.walkECLScope = function (parentStack, scope) {
var info = this.buildStack(parentStack, scope.name, true);
this._test.set(info.qid, scope);
for (var _i = 0, _a = scope.definitions; _i < _a.length; _i++) {
var def = _a[_i];
this.walkDefinition(info.stack, def);
}
};
Workspace.prototype.walkField = function (parentStack, field) {
var info = this.buildStack(parentStack, field.name, false);
this._test.set(info.qid, field);
};
Workspace.prototype.walkDefinition = function (parentStack, definition) {
var info = this.buildStack(parentStack, definition.name, true);
this.walkECLScope(parentStack, definition);
for (var _i = 0, _a = definition.fields; _i < _a.length; _i++) {
var field = _a[_i];
this.walkField(info.stack, field);
}
};
Workspace.prototype.walkSource = function (source) {
// const dirName = path.dirname(source.sourcePath);
// const relName = path.relative(this._workspacePath, dirName).split(path.sep).join(".");
// const folder = new Folder(relName, dirName);
// this._test.set(folder.name, folder);
this.walkECLScope([], source);
};
Workspace.prototype.parseSources = function (sources) {
if (sources === void 0) { sources = []; }
for (var _i = 0, sources_1 = sources; _i < sources_1.length; _i++) {
var _source = sources_1[_i];
if (_source.$.name) { // Plugins have no name...
var source = new Source(_source);
inspect(_source, "source", source);
this._sourceByID.set(source.name, source);
this._sourceByPath.set(source.sourcePath, source);
// If external source like "std.system.ThorLib" then need to backup to "std" and add its folder
if (source.name) {
var sourceNameParts = source.name.split(".");
var depth = sourceNameParts.length;
if (depth > 1) {
var sourcePath = source.sourcePath;
while (depth > 1) {
sourcePath = path.dirname(sourcePath);
--depth;
}
this.visitFolder(sourcePath, path.dirname(sourcePath));
}
}
this.walkSource(source);
}
}
};
Workspace.prototype.parseMetaXML = function (metaXML) {
var metaParser = new MetaParser();
metaParser.parse(metaXML);
this.parseSources(metaParser.sources);
return metaParser.sources.map(function (source) { return path.normalize(source.$.sourcePath); });
};
Workspace.prototype.resolveQualifiedID = function (filePath, qualifiedID, charOffset) {
var retVal;
if (!retVal && this._test.has(qualifiedID)) {
retVal = this._test.get(qualifiedID).scope;
}
if (!retVal && this._sourceByPath.has(filePath)) {
var eclSource = this._sourceByPath.get(filePath);
// Resolve Imports ---
var qualifiedIDParts = qualifiedID.split(".");
for (var _i = 0, _a = eclSource.imports; _i < _a.length; _i++) {
var imp = _a[_i];
if (imp.name.toLowerCase() === qualifiedIDParts[0].toLowerCase()) {
if (imp.ref) {
qualifiedIDParts[0] = imp.ref;
}
else {
qualifiedIDParts.shift();
}
break;
}
}
var realQID = qualifiedIDParts.join(".");
if (!retVal && this._test.has(realQID)) {
retVal = this._test.get(realQID).scope;
}
if (!retVal) {
realQID = __spreadArray(__spreadArray([], eclSource.name.split("."), true), qualifiedIDParts, true).join(".");
if (this._test.has(realQID)) {
retVal = this._test.get(realQID).scope;
}
}
}
return retVal;
};
Workspace.prototype.resolvePartialID = function (filePath, partialID, charOffset) {
partialID = partialID.toLowerCase();
var partialIDParts = partialID.split(".");
partialIDParts.pop();
var partialIDQualifier = partialIDParts.length === 1 ? partialIDParts[0] : partialIDParts.join(".");
return this.resolveQualifiedID(filePath, partialIDQualifier, charOffset);
};
return Workspace;
}());
export { Workspace };
var workspaceCache = new Dictionary();
export function attachWorkspace(_workspacePath, eclccPath) {
var workspacePath = path.normalize(_workspacePath);
if (!workspaceCache.has(workspacePath)) {
var workspace = new Workspace(workspacePath, eclccPath);
workspaceCache.set(workspacePath, workspace);
workspace.refresh();
}
return workspaceCache.get(workspacePath);
}
function isQualifiedIDChar(lineText, charPos, reverse) {
if (charPos < 0)
return false;
var testChar = lineText.charAt(charPos);
return (reverse ? /[a-zA-Z\d_\.$]/ : /[a-zA-Z\d_]/).test(testChar);
}
export function qualifiedIDBoundary(lineText, charPos, reverse) {
while (isQualifiedIDChar(lineText, charPos, reverse)) {
charPos += reverse ? -1 : 1;
}
return charPos + (reverse ? 1 : -1);
}
var MetaParser = /** @class */ (function (_super) {
__extends(MetaParser, _super);
function MetaParser() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.sources = [];
return _this;
}
MetaParser.prototype.endXMLNode = function (e) {
switch (e.name) {
case "Source":
this.sources.push(e);
break;
default:
break;
}
_super.prototype.endXMLNode.call(this, e);
};
return MetaParser;
}(SAXStackParser));
//# sourceMappingURL=eclMeta.js.map