maestro-cli-roku
Version:
command line tools for maestro-roku projects
468 lines (467 loc) • 24.7 kB
JavaScript
"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;