UNPKG

maestro-cli-roku

Version:

command line tools for maestro-roku projects

288 lines (287 loc) 13.9 kB
'use strict'; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; Object.defineProperty(exports, "__esModule", { value: true }); var FileType_1 = require("../fileProcessing/FileType"); var ProcessorSettings_1 = require("../fileProcessing/ProcessorSettings"); var ChangeExtension_1 = require("../utils/ChangeExtension"); var Feedback_1 = require("../utils/Feedback"); var Utils_1 = require("../utils/Utils"); /** * Manages importing includes for a given brs file */ var ImportProcessor = /** @class */ (function () { function ImportProcessor(projectProcessor) { this.importRegex = new RegExp("^(?: *|\\t*)import\\s*\\\"(.*)\\\"", "gim"); this.importTemplate = "<script type=\"text/brightscript\" uri=\"$PATH$\" />"; this.endOfXmlFileRegex = new RegExp("</component>", "gim"); this.settings = new ProcessorSettings_1.ProcessorSettings(); this.config = projectProcessor.config; this.fileMap = projectProcessor.fileMap; this.projectProcessor = projectProcessor; } ImportProcessor.prototype.addImportsToXmlFile = function (file) { if (!file || file.fileType !== FileType_1.FileType.Xml && file.fileType !== FileType_1.FileType.ViewXml) { throw new Error('was given a non-xml file'); } if (!file.hasProcessedImports) { if (file.parentFile && !file.parentFile.hasProcessedImports) { //we must process and update the parent first, otherwise we can't filter the imports this.addImportsToXmlFile(file.parentFile); } this.identifyImports(file); this.addImportCodeToFile(file); file.hasProcessedImports = true; } }; ImportProcessor.prototype.parseFileImports = function (file) { Utils_1.addSetItems(file.importedPaths, this.getFileImports(file, Utils_1.getRegexMatchesValues(file.getFileContents(), this.importRegex, 1))); }; ImportProcessor.prototype.getFileImports = function (file, paths) { var _this = this; var importPaths = []; var filePath = file.pkgPath.toLowerCase(); paths.forEach(function (path) { if (path.toLowerCase().indexOf('build:/') === 0) { _this.addBuildImportPaths(file, filePath, path, importPaths); } else { _this.addImportPath(filePath, path.toLowerCase(), importPaths); } }); return importPaths; }; ImportProcessor.prototype.addBuildImportPaths = function (file, filePath, buildKey, target) { var _this = this; var imports = this.config.buildTimeImports ? this.config.buildTimeImports[buildKey.substr(7)] : null; if (imports) { imports.forEach(function (p) { return _this.addImportPath(filePath, p.toLowerCase(), target); }); } else { Feedback_1.feedbackError(file, "xml file imports a build time import key that was not defined in your config:file that cannot be found " + buildKey, true); } }; ImportProcessor.prototype.addImportPath = function (filePath, path, target) { var normalizedPath = Utils_1.getPkgPathFromTarget(filePath, path); if (normalizedPath) { //.bs imports become .brs imports, as they will be compiled prior to resolution if (normalizedPath.toLowerCase().endsWith('.bs')) { normalizedPath = ChangeExtension_1.changeExtension(normalizedPath, '.brs'); } target.push(normalizedPath); } }; ImportProcessor.prototype.identifyImports = function (file) { var e_1, _a, e_2, _b, e_3, _c; if (!file || file.fileType !== FileType_1.FileType.Xml && file.fileType !== FileType_1.FileType.ViewXml) { throw new Error('was given a non-xml file'); } var rootImportPaths = new Set(); //1 add codebehind imports if (file.associatedFile) { Utils_1.addSetItems(rootImportPaths, file.associatedFile.importedPaths); } //2 add imported paths from all XML imported scripts var xmlFile = file.programFile; try { for (var _d = __values(xmlFile.getOwnScriptImports()), _e = _d.next(); !_e.done; _e = _d.next()) { var fileReference = _e.value; var importedFile = this.fileMap.getFileByPkgPath(fileReference.pkgPath); if (!importedFile) { //theres's a bug in brs that can sometimes set the absolute path to pkg path importedFile = this.fileMap.getFile(fileReference.pkgPath); } if (!importedFile) { if (this.isImportSkipped(fileReference.pkgPath)) { file.importedPaths.add(fileReference.pkgPath); Feedback_1.feedbackWarning(file, "xml file imports nonchecked file that is not available: " + fileReference.pkgPath, false, 'import'); continue; } else { Feedback_1.feedbackError(file, "xml file imports a file that cannot be found " + fileReference.pkgPath); continue; } } else if (importedFile === file.associatedFile) { continue; } Utils_1.addSetItems(rootImportPaths, importedFile.importedPaths); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_e && !_e.done && (_a = _d.return)) _a.call(_d); } finally { if (e_1) throw e_1.error; } } //3 identify if the file is using bindings if (file.bindings.length > 0) { rootImportPaths.add('source/maestro/observable/ObservableMixin.brs'); rootImportPaths.add('source/maestro/observable/BaseObservable.brs'); } if (this.config.createRuntimeFiles) { rootImportPaths.add('source/MRuntime.brs'); } //5 get all nested dependencies var allImportedPaths = new Set(); try { for (var rootImportPaths_1 = __values(rootImportPaths), rootImportPaths_1_1 = rootImportPaths_1.next(); !rootImportPaths_1_1.done; rootImportPaths_1_1 = rootImportPaths_1.next()) { var importPath = rootImportPaths_1_1.value; this.addNestedImportPaths(file, importPath, allImportedPaths); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (rootImportPaths_1_1 && !rootImportPaths_1_1.done && (_b = rootImportPaths_1.return)) _b.call(rootImportPaths_1); } finally { if (e_2) throw e_2.error; } } //turn all imports into files var requiredFiles = []; var importedFiles = []; var parentImportPaths = file.getAllParentImportPathsAsSet(); try { for (var allImportedPaths_1 = __values(allImportedPaths), allImportedPaths_1_1 = allImportedPaths_1.next(); !allImportedPaths_1_1.done; allImportedPaths_1_1 = allImportedPaths_1.next()) { var path = allImportedPaths_1_1.value; var importedFile = this.fileMap.getFileByPkgPath(path); if (importedFile) { requiredFiles.push(importedFile); if (!parentImportPaths.has(path.toLowerCase())) { importedFiles.push(importedFile); } } else if (!this.isImportSkipped(path)) { this.failWithMissingImport(file, path); } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (allImportedPaths_1_1 && !allImportedPaths_1_1.done && (_c = allImportedPaths_1.return)) _c.call(allImportedPaths_1); } finally { if (e_3) throw e_3.error; } } file.importedFiles = importedFiles; file.requiredFiles = requiredFiles; }; ImportProcessor.prototype.addNestedImportPaths = function (sourceFile, parentPkgPath, importPaths, parentSet) { var e_4, _a; if (parentSet === void 0) { parentSet = null; } var parentFile = this.fileMap.getFileByPkgPath(parentPkgPath); if (!parentFile) { if (this.isImportSkipped(parentPkgPath)) { Feedback_1.feedbackWarning(sourceFile, "xml file imports nonchecked file that is not available: " + parentPkgPath, false, 'import'); importPaths.add(parentPkgPath); return; } else { this.failWithMissingImport(sourceFile, parentPkgPath); return; } } if (!parentSet) { parentSet = new Set([parentPkgPath]); } var file = parentFile; try { for (var _b = __values(file.importedPaths), _c = _b.next(); !_c.done; _c = _b.next()) { var importPath = _c.value; if (!importPaths.has(importPath)) { var importFile = this.fileMap.getFileByPkgPath(importPath); if (!importFile) { if (this.isImportSkipped(importPath)) { Feedback_1.feedbackWarning(file, "xml file imports nonchecked file that is not available: " + importPath, false, 'import'); break; } else { this.failWithMissingImport(file, importPath); return; } } if (parentSet.has(importPath)) { this.failWithCyclicalImport(file, parentPkgPath, importPath); } var importStack = new Set(parentSet); importStack.add(importPath); this.addNestedImportPaths(file, importPath, importPaths, importStack); } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_4) throw e_4.error; } } importPaths.add(parentPkgPath); }; ImportProcessor.prototype.failWithMissingImport = function (file, path) { Feedback_1.feedbackError(file, "Missing import - could not find a file at path " + path); }; ImportProcessor.prototype.failWithCyclicalImport = function (file, sourceImportPath, path) { Feedback_1.feedbackError(file, "Cyclical import detected - an infinite import cycle\n was found on " + path + " when processing import for " + sourceImportPath, true); }; /** * Responsible for updating the codebehind and xml files with the required imports */ ImportProcessor.prototype.addImportCodeToFile = function (file) { //for viewxml/codebehind files, we add the imports to xml - for pure brs files that's a moot point if (file.fileType === FileType_1.FileType.Xml || file.fileType === FileType_1.FileType.ViewXml) { this.addImportIncludesToXML(file); } }; ImportProcessor.prototype.addImportIncludesToXML = function (file) { var _this = this; if (file.fileType !== FileType_1.FileType.Xml && file.fileType !== FileType_1.FileType.ViewXml) { Feedback_1.feedbackError(file, "Was passed a non xml file", true); } var imports = ""; var cwd = process.cwd(); file.importedFiles.forEach(function (file) { imports += "\n" + _this.importTemplate.replace("$PATH$", file.pkgUri); }); //if the codebehind is not imported yet, import it var xmlFile = file.programFile; if (file.associatedFile) { var codeBehindPkgPath_1 = file.associatedFile.pkgPath.toLowerCase(); var ownScripts = xmlFile.getOwnScriptImports(); if (!ownScripts.find(function (i) { return i.pkgPath.toLowerCase() === codeBehindPkgPath_1; })) { imports += "\n" + this.importTemplate.replace("$PATH$", file.associatedFile.pkgUri); } } //we place imports at the end of the file to ensure we don't screw up error line number reporting var xmlContents = file.getFileContents(); this.endOfXmlFileRegex.lastIndex = 0; var result = this.endOfXmlFileRegex.exec(xmlContents); if (imports.length > 0) { if (result) { var insertionIndex = result.index; //TODO - get the end tag location, and put it on the line before xmlContents = Utils_1.spliceString(xmlContents, insertionIndex, imports); xmlContents += '\n</component>'; file.setFileContents(xmlContents); file.saveFileContents(); } else { Feedback_1.feedbackError(file, "xml file did not have end component tag"); } } }; ImportProcessor.prototype.isImportSkipped = function (pkgPath) { return this.config.nonCheckedImports ? this.config.nonCheckedImports.some(function (i) { return i.toLowerCase().endsWith(pkgPath.toLowerCase()); }) : false; }; return ImportProcessor; }()); exports.default = ImportProcessor;