UNPKG

@hpcc-js/comms

Version:
463 lines 18.3 kB
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