UNPKG

maestro-cli-roku

Version:

command line tools for maestro-roku projects

468 lines (467 loc) 24.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; 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 }); // @ts-ignore // @ts-ignore var brightscript_language_1 = require("brightscript-language"); var Debug = require("debug"); var fs = require("fs-extra"); var path = require("path"); // tslint:disable-next-line:origin-ordered-imports var util_1 = require("util"); var BindingProcessor_1 = require("../bindingSupport/BindingProcessor"); var ClassProcessor_1 = require("../classSupport/ClassProcessor"); var ImportProcessor_1 = require("../importSupport/ImportProcessor"); var NamespaceProcessor_1 = require("../namespaceSupport/NamespaceProcessor"); var ChangeExtension_1 = require("../utils/ChangeExtension"); var Feedback_1 = require("../utils/Feedback"); var Utils_1 = require("../utils/Utils"); var File_1 = require("./File"); var FileType_1 = require("./FileType"); var ProcessorConfig_1 = require("./ProcessorConfig"); var ProcessorSettings_1 = require("./ProcessorSettings"); var ProjectFileMap_1 = require("./ProjectFileMap"); var promisify = require('util').promisify; var exec = promisify(require('child_process').exec); var debug = Debug('projectProcessor'); var ProjectProcessor = /** @class */ (function () { function ProjectProcessor(config, fileMap) { this._config = config; debug('Running project processor'); this._builderConfig = { // cwd: this.config.sourcePath, files: this.config.filePattern, rootDir: this.config.outputPath }; if (!config.sourcePaths) { throw new Error('Config does not contain sourcePaths property - you must provide an array of sourcepaths.'); } if (!config.outputPath) { throw new Error('Config does not contain outputPath property'); } this._targetPath = path.resolve(this._config.outputPath); this._fileMap = fileMap || new ProjectFileMap_1.ProjectFileMap(this._config.createRuntimeFiles); this._settings = new ProcessorSettings_1.ProcessorSettings(); this._importProcessor = new ImportProcessor_1.default(this); this._classProcessor = new ClassProcessor_1.default(this); this._namespaceProcessor = new NamespaceProcessor_1.NamespaceProcessor(this); } Object.defineProperty(ProjectProcessor.prototype, "targetPath", { get: function () { return this._targetPath; }, enumerable: true, configurable: true }); Object.defineProperty(ProjectProcessor.prototype, "config", { get: function () { return this._config; }, enumerable: true, configurable: true }); Object.defineProperty(ProjectProcessor.prototype, "settings", { get: function () { return this._settings; }, enumerable: true, configurable: true }); Object.defineProperty(ProjectProcessor.prototype, "fileMap", { get: function () { return this._fileMap; }, enumerable: true, configurable: true }); ProjectProcessor.prototype.processFiles = function () { return __awaiter(this, void 0, void 0, function () { var warnings; return __generator(this, function (_a) { switch (_a.label) { case 0: debug("Running processor with config " + util_1.inspect(this.config) + " "); this.clearFiles(); return [4 /*yield*/, this.copyFiles()]; case 1: _a.sent(); //1. create files, which compiles brighterscript return [4 /*yield*/, this.createFiles()]; case 2: //1. create files, which compiles brighterscript _a.sent(); //2 validate overrides etc this._classProcessor.validateClasses(); //3. we are now ready to fully construct, as we have the parent file references this._classProcessor.addClassConstructors(); this.processNamespaceUsage(); this.processBindings(); this.processImports(); this.saveChangedFiles(); if (this.config.createRuntimeFiles) { this.createUtilFile(); } console.log('\nComplete\n'); if (Feedback_1.getFeedbackErrors().length > 0) { console.log('Compilation failed due to the following errors'); Feedback_1.getFeedbackErrors().forEach(function (e) { return console.log(e.toString()); }); throw new Error('compilation failed'); } warnings = Feedback_1.getFeedbackWarnings().filter(function (w) { return w.category !== 'import'; }); if (warnings.length > 0 && this.config.logLevel >= ProcessorConfig_1.ProcessorLogLevel.warning) { console.log('The following warnings were encountered during processing'); warnings.forEach(function (e) { return console.log(e.toString()); }); } if (Feedback_1.getFeedbackInfos().length > 0 && this.config.logLevel >= ProcessorConfig_1.ProcessorLogLevel.info) { console.log('The following info messages were encountered during processing'); Feedback_1.getFeedbackInfos().forEach(function (e) { return console.log(e.toString()); }); } if (Feedback_1.getFeedbackVerbose().length > 0 && this.config.logLevel >= ProcessorConfig_1.ProcessorLogLevel.verbose) { console.log('The following verbose messages were encountered during processing'); Feedback_1.getFeedbackVerbose().forEach(function (e) { return console.log(e.toString()); }); } return [2 /*return*/]; } }); }); }; ProjectProcessor.prototype.processImports = function () { var _this = this; debug("Processing imports "); this.fileMap .getAllFiles() .filter(function (file) { return !file.isProcessingDisabled && (file.fileType === FileType_1.FileType.Xml || file.fileType === FileType_1.FileType.ViewXml); }) .forEach(function (file) { _this._importProcessor.addImportsToXmlFile(file); }); }; ProjectProcessor.prototype.processNamespaceUsage = function () { var _this = this; debug("Processing namespace usage "); this.fileMap .getAllFiles() .filter(function (file) { return file.isCompiledBrs && !file.isProcessingDisabled; }) .forEach(function (file) { return _this._namespaceProcessor.processNamespaceUsage(file); }); }; ProjectProcessor.prototype.processBindings = function () { debug("Processing bindings "); var bindingProcessor = new BindingProcessor_1.BindingProcessor(); this.fileMap .getAllFiles() .filter(function (file) { return !file.isProcessingDisabled && (file.fileType === FileType_1.FileType.Xml || file.fileType === FileType_1.FileType.ViewXml); }) .forEach(function (file) { bindingProcessor.processFile(file); }); }; ProjectProcessor.prototype.saveChangedFiles = function () { debug("saving all changed files "); this.fileMap .getAllFiles() .filter(function (file) { return file.isDirty; }) .forEach(function (file) { file.saveFileContents(); }); }; ProjectProcessor.prototype.copyFiles = function () { return __awaiter(this, void 0, void 0, function () { var oldPath, outPath, sourcePaths, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: oldPath = path.resolve(process.cwd()); _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); outPath = path.resolve(this.config.outputPath); fs.mkdirSync(this.config.outputPath); sourcePaths = this.config.sourcePaths.map(function (p) { p = path.resolve(p); p = p.endsWith('/') ? p : p + '/'; if (!fs.existsSync(p)) { Feedback_1.feedbackError(new File_1.File(p, '', '', ''), "cannot find source path " + p, true); } return p; }).join(' '); return [4 /*yield*/, exec("rsync -az " + sourcePaths + " " + outPath)]; case 2: _a.sent(); console.log("files copied to " + outPath + " dir is now " + process.cwd()); return [3 /*break*/, 4]; case 3: err_1 = _a.sent(); console.error(err_1); return [3 /*break*/, 4]; case 4: process.chdir(oldPath); return [2 /*return*/]; } }); }); }; /** * Find all files inside a dir, recursively and convert to files * @function getAllFiles * @return {string[]} Array with all file names that are inside the directory. * @param directory */ ProjectProcessor.prototype.createFiles = function () { return __awaiter(this, void 0, void 0, function () { var directory, normalizedOptions, glob, files_2, files, files_1, files_1_1, file, extension, projectPath, fullPath, filename, fsPath, existingFile, e_1, e_2_1; var e_2, _a; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: directory = this.config.outputPath; debug("Creating file files processor at path " + directory + " "); return [4 /*yield*/, brightscript_language_1.util.normalizeAndResolveConfig(this._builderConfig)]; case 1: normalizedOptions = _b.sent(); this._program = new brightscript_language_1.Program(normalizedOptions); glob = require('glob-all'); console.log('Processor is working with config ' + util_1.inspect(this.config)); console.time('processingExcludedPaths:'); if (this.config.processingExcludedPaths && this.config.processingExcludedPaths.length > 0) { files_2 = glob.sync(this.config.processingExcludedPaths, { cwd: this.config.outputPath }); Utils_1.addSetItems(this.fileMap.nonProcessFilePaths, files_2.map(function (file) { //console.log('found processing excluded file ' + file); var projectPath = path.dirname(file); var fullPath = path.join(_this.targetPath, projectPath); var filename = path.basename(file); return path.join(fullPath, filename).toLowerCase(); })); } console.timeEnd('processingExcludedPaths:'); console.time('filePattern:'); files = glob.sync(this.config.filePattern, { cwd: this.config.outputPath }); _b.label = 2; case 2: _b.trys.push([2, 9, 10, 11]); files_1 = __values(files), files_1_1 = files_1.next(); _b.label = 3; case 3: if (!!files_1_1.done) return [3 /*break*/, 8]; file = files_1_1.value; extension = path.extname(file).toLowerCase(); if (!(extension === '.brs' || extension === '.xml' || extension === '.bs')) return [3 /*break*/, 7]; projectPath = path.dirname(file); fullPath = path.join(this.targetPath, projectPath); filename = path.basename(file); fsPath = path.join(fullPath, filename); existingFile = this.fileMap.getFile(fsPath); if (!!existingFile) return [3 /*break*/, 7]; _b.label = 4; case 4: _b.trys.push([4, 6, , 7]); return [4 /*yield*/, this.createFile(fullPath, projectPath, filename, extension)]; case 5: _b.sent(); return [3 /*break*/, 7]; case 6: e_1 = _b.sent(); //log the error, but don't fail this process because the file might be fixable later console.error(e_1); return [3 /*break*/, 7]; case 7: files_1_1 = files_1.next(); return [3 /*break*/, 3]; case 8: return [3 /*break*/, 11]; case 9: e_2_1 = _b.sent(); e_2 = { error: e_2_1 }; return [3 /*break*/, 11]; case 10: try { if (files_1_1 && !files_1_1.done && (_a = files_1.return)) _a.call(files_1); } finally { if (e_2) throw e_2.error; } return [7 /*endfinally*/]; case 11: console.timeEnd('filePattern:'); //Set parents console.time('parents:'); this.fileMap .getAllFiles() .filter(function (file) { return file.fileType === FileType_1.FileType.Xml || file.fileType === FileType_1.FileType.ViewXml; }) .forEach(function (file) { // console.log('add parent ' + file.filename); if (file.programFile) { var parent_1 = file.programFile.parent; if (parent_1) { file.parentFile = _this.fileMap.getFile(parent_1.pathAbsolute); } } else { console.error("Missing xml program file for " + file.filename); } }); console.timeEnd('parents:'); debug("finished creating file files"); return [2 /*return*/]; } }); }); }; /** * Create desciptor for the given file - * @param directory * @param filename * @param associatedFile */ ProjectProcessor.prototype.createFile = function (fullPath, projectPath, filename, extension, associatedFile) { if (associatedFile === void 0) { associatedFile = null; } return __awaiter(this, void 0, void 0, function () { var file, associatedFile_1, _a, e_3; return __generator(this, function (_b) { switch (_b.label) { case 0: file = new File_1.File(fullPath, projectPath, filename, extension); file.isProcessingDisabled = this.fileMap.nonProcessFilePaths.has(file.fullPath.toLowerCase()); if (file.fileType === FileType_1.FileType.UncompiledBrighterscript) { if (!file.isProcessingDisabled) { file.convertToBrightScript(this._classProcessor, this._namespaceProcessor, this._importProcessor); } else { Feedback_1.feedbackWarning(file, 'File is brighterscript; but is included in files not to be processed - it will not be converted to brightscript!'); } } if (!!file.associatedFile) return [3 /*break*/, 3]; if (!!associatedFile) return [3 /*break*/, 2]; return [4 /*yield*/, this.getAssociatedFile(file)]; case 1: associatedFile_1 = _b.sent(); // console.log('SET ASSOC ' + file.filename + ' - ' + (associatedFile ? associatedFile.filename : 'NO FILE')); file.associatedFile = associatedFile_1; return [3 /*break*/, 3]; case 2: // console.log('SET ASSOC 2 ' + file.filename + ' - ' + (associatedFile ? associatedFile.filename : 'NO FILE')); file.associatedFile = associatedFile; _b.label = 3; case 3: if ((file.fileType === FileType_1.FileType.ViewXml || file.fileType === FileType_1.FileType.Xml) && !file.isProcessingDisabled) { file.convertBrighterScriptXMLImports(); } if (!(file.fileType === FileType_1.FileType.ViewXml || file.fileType === FileType_1.FileType.Xml)) return [3 /*break*/, 7]; _b.label = 4; case 4: _b.trys.push([4, 6, , 7]); _a = file; return [4 /*yield*/, this._program.addOrReplaceFile(file.fullPath.toLowerCase(), file.getFileContents())]; case 5: _a.programFile = _b.sent(); file.loadXmlContents(this.fileMap); return [3 /*break*/, 7]; case 6: e_3 = _b.sent(); console.error("Error processing xml " + file.filename + " file " + e_3.message); return [3 /*break*/, 7]; case 7: // console.log('>>ADDING FILE', file.filename); this.fileMap.addFile(file); return [2 /*return*/, file]; } }); }); }; ProjectProcessor.prototype.getAssociatedFile = function (file) { return __awaiter(this, void 0, void 0, function () { var otherExtension, otherFilename, otherPath, associatedFile; return __generator(this, function (_a) { switch (_a.label) { case 0: // console.log('GET ASSOC' + file.filename); if (file.extension !== '.brs' && file.extension !== '.xml') { return [2 /*return*/, null]; } otherExtension = file.extension === '.brs' ? '.xml' : '.brs'; otherFilename = ChangeExtension_1.changeExtension(file.filename, otherExtension); otherPath = path.join(file.fsPath, otherFilename); associatedFile = this.fileMap.getFile(otherPath); if (!!associatedFile) return [3 /*break*/, 2]; if (!fs.existsSync(otherPath)) return [3 /*break*/, 2]; return [4 /*yield*/, this.createFile(file.fsPath, file.projectPath, otherFilename, otherExtension, file)]; case 1: associatedFile = _a.sent(); _a.label = 2; case 2: return [2 /*return*/, associatedFile]; } }); }); }; ProjectProcessor.prototype.clearFiles = function () { fs.removeSync(this.config.outputPath); }; ProjectProcessor.prototype.createUtilFile = function () { var filePath = path.join(this.config.outputPath, 'source'); console.log("Creating runtime util file at " + filePath + "/MRuntime.brs"); var file = new File_1.File(filePath, 'source', 'MRuntime.brs', '.brs'); var text = "\n ' Generated by maestro framework - this class contains runtime library files\n " + this._classProcessor.getClassMapFunction('MRuntime') + "\n " + this._fileMap.getXMLCompTypesFunction('MRuntime') + "\n "; file.setFileContents(text); file.saveFileContents(); }; return ProjectProcessor; }()); exports.ProjectProcessor = ProjectProcessor;