maestro-cli-roku
Version:
command line tools for maestro-roku projects
562 lines (561 loc) • 31.9 kB
JavaScript
;
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 __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });
var chai_1 = require("chai");
var chai = require("chai");
var _ = require("lodash");
var path = require("path");
var File_1 = require("../fileProcessing/File");
var ProjectFileMap_1 = require("../fileProcessing/ProjectFileMap");
var ProjectProcessor_1 = require("../fileProcessing/ProjectProcessor");
var Feedback_1 = require("../utils/Feedback");
var Feedback_2 = require("../utils/Feedback");
var Utils_1 = require("../utils/Utils");
var ImportProcessor_1 = require("./ImportProcessor");
var chaiSubset = require('chai-subset');
chai.use(chaiSubset);
var config = require('../../test/testProcessorConfig.json');
var processor;
var fileMap;
var importFilesPath = path.join('components', 'screens', 'imports');
var importProcessor;
describe('Include importProcessor', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
Feedback_2.resetFeedback();
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
return [2 /*return*/];
}
});
}); });
describe('Initialization', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
Feedback_2.resetFeedback();
return [2 /*return*/];
});
}); });
it('initializes with valid processor', function () {
chai_1.expect(importProcessor).to.not.be.null;
});
});
describe('addImportsToXmlFile file failures', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
Feedback_2.resetFeedback();
return [2 /*return*/];
});
}); });
it('fails with brs file', function () {
var file = createFile(importFilesPath, '.brs');
chai_1.expect(function () { return new ImportProcessor_1.default(processor).addImportsToXmlFile(file); }).to.throw(Error);
});
it('fails with other file', function () {
var file = createFile(importFilesPath, '.png');
chai_1.expect(function () { return new ImportProcessor_1.default(processor).addImportsToXmlFile(file); }).to.throw(Error);
});
});
describe('identifyImports', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
Feedback_2.resetFeedback();
return [2 /*return*/];
});
}); });
it('identifies 1 import', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/test.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.importedFiles).to.have.lengthOf(2);
chai_1.expect(file.requiredFiles).to.have.lengthOf(2);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members([
'FocusMixin.brs',
'MRuntime.brs'
]);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('does not include runtime files when disabled in config', function () { return __awaiter(_this, void 0, void 0, function () {
var config2, processor, file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config2 = _.clone(config);
config2.createRuntimeFiles = false;
processor = new ProjectProcessor_1.ProjectProcessor(config2, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/test.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.importedFiles).to.have.lengthOf(1);
chai_1.expect(file.requiredFiles).to.have.lengthOf(1);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members([
'FocusMixin.brs'
]);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
return [2 /*return*/];
}
});
}); });
it('identifies 2 imports', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/test2Imports.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.requiredFiles).to.have.lengthOf(3);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members([
'FocusMixin.brs', 'TextMixin.brs', 'MRuntime.brs'
]);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
describe('missing imports', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
Feedback_2.resetFeedback();
return [2 /*return*/];
});
}); });
it('reports error on missing import', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testMissingImport.xml');
importProcessor.identifyImports(file);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('reports error on cascading missing import', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testCascadingMissingImport.xml');
importProcessor.identifyImports(file);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('reports error on missing import in xml', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testMissingImportTag.xml');
importProcessor.identifyImports(file);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('continues on import which is flagged as unchecked', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
config.nonCheckedImports = [
'source/tests/rooibosDist.brs'.toLowerCase(),
'source/tests/rooibosFunctionMap.brs'.toLowerCase()
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testNoCheck.xml');
chai_1.expect(function () { return importProcessor.identifyImports(file); }).to.not.throw(Error);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
chai_1.expect(Feedback_1.getFeedbackWarnings()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('continues on cascading import which is flagged as unchecked', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
config.nonCheckedImports = [
'source/tests/rooibosDist.brs'.toLowerCase(),
'source/tests/rooibosFunctionMap.brs'.toLowerCase()
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testNoCheckBs.xml');
importProcessor.identifyImports(file);
// expect(() => importProcessor.identifyImports(file)).to.not.throw(Error);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
chai_1.expect(Feedback_1.getFeedbackWarnings()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('continues on missing xml import which is flagged as unchecked', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
config.nonCheckedImports = [
'source/tests/rooibosDist.brs'.toLowerCase(),
'source/tests/rooibosFunctionMap.brs'.toLowerCase()
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testNoCheck.xml');
// importProcessor.identifyImports(file);
chai_1.expect(function () { return importProcessor.identifyImports(file); }).to.not.throw(Error);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
return [2 /*return*/];
}
});
}); });
});
it('identifies cascading imports', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/testCascadingImports.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.requiredFiles).to.have.lengthOf(4);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members([
'Utils.brs', 'LogMixin.brs', 'NetMixin.brs', 'MRuntime.brs'
]);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('reports error on cascading missing import', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testMissingImport.xml');
importProcessor.identifyImports(file);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('reports error on cyclical import', function () { return __awaiter(_this, void 0, void 0, function () {
var file;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
fileMap = new ProjectFileMap_1.ProjectFileMap();
config = _.clone(config);
config.filePattern = [
'**/*.bs',
'**/*.brs',
'**/*.xml',
'!**/excluded/**/*'
];
processor = new ProjectProcessor_1.ProjectProcessor(config, fileMap);
processor.clearFiles();
return [4 /*yield*/, processor.copyFiles()];
case 1:
_a.sent();
return [4 /*yield*/, processor.createFiles()];
case 2:
_a.sent();
importProcessor = new ImportProcessor_1.default(processor);
file = processor.fileMap.getFileByPkgPath('components/screens/imports/testCyclicalImport.xml');
chai_1.expect(function () { return importProcessor.identifyImports(file); }).to.throw(Error);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.not.be.empty;
return [2 /*return*/];
}
});
}); });
it('parent class includes imports', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.requiredFiles).to.have.lengthOf(2);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members(['FocusMixin.brs', 'MRuntime.brs']);
chai_1.expect(file.importedFiles).to.have.lengthOf(2);
chai_1.expect(file.importedFiles.map(function (file) { return file.filename; })).to.have.all.members(['FocusMixin.brs', 'MRuntime.brs']);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('include subclass imports', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension2.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.requiredFiles).to.have.lengthOf(4);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members([
'Utils.brs', 'LogMixin.brs', 'NetMixin.brs', 'MRuntime.brs'
]);
chai_1.expect(file.importedFiles).to.have.lengthOf(4);
chai_1.expect(file.importedFiles.map(function (file) { return file.filename; })).to.have.all.members([
'Utils.brs', 'LogMixin.brs', 'NetMixin.brs', 'MRuntime.brs'
]);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('exclude parent imports in second subclass', function () {
//make sure we process the parents in order, so they have their namespaces set
var fileRoot = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension.xml');
importProcessor.identifyImports(fileRoot);
var fileParent = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension2.xml');
importProcessor.identifyImports(fileParent);
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension3.xml');
importProcessor.identifyImports(file);
chai_1.expect(file.requiredFiles).to.have.lengthOf(3);
chai_1.expect(file.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members(['TextMixin.brs', 'FocusMixin.brs', 'MRuntime.brs']);
chai_1.expect(file.importedFiles).to.have.lengthOf(1);
chai_1.expect(file.importedFiles.map(function (file) { return file.filename; })).to.have.all.members(['TextMixin.brs']);
var topFile = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension4.xml');
importProcessor.identifyImports(topFile);
chai_1.expect(topFile.requiredFiles).to.have.lengthOf(7);
chai_1.expect(topFile.requiredFiles.map(function (file) { return file.filename; })).to.have.all.members(['TextMixin.brs', 'FocusMixin.brs', 'NetMixin.brs', 'LogMixin.brs', 'AuthMixin.brs', 'Utils.brs', 'MRuntime.brs']);
chai_1.expect(topFile.importedFiles.map(function (file) { return file.filename; })).to.have.all.members(['AuthMixin.brs']);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
});
describe('addImportIncludesToXML', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
Feedback_2.resetFeedback();
return [2 /*return*/];
});
}); });
it('adds script tags for 1 import', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/test.xml');
importProcessor.addImportsToXmlFile(file);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('adds script tags for cascading imports', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/testCascadingImports.xml');
importProcessor.addImportsToXmlFile(file);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('adds script tags for extended imports', function () {
var fileRoot = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension.xml');
var fileParent = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension2.xml');
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension3.xml');
var topFile = processor.fileMap.getFileByPkgPath('components/screens/imports/testExtension4.xml');
importProcessor.addImportsToXmlFile(topFile);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
var fileRootScriptTags = getXMLScriptImportNamesFromFile(fileRoot);
var fileParentScriptTags = getXMLScriptImportNamesFromFile(fileParent);
var fileScriptTags = getXMLScriptImportNamesFromFile(file);
var topFileScriptTags = getXMLScriptImportNamesFromFile(topFile);
chai_1.expect(fileRootScriptTags).to.have.all.members(['FocusMixin.brs', 'testExtension.brs', 'MRuntime.brs']);
chai_1.expect(fileParentScriptTags).to.have.all.members(['Utils.brs', 'LogMixin.brs', 'NetMixin.brs', 'testExtension2.brs']);
chai_1.expect(fileScriptTags).to.have.all.members(['TextMixin.brs', 'testExtension3.brs']);
chai_1.expect(topFileScriptTags).to.have.all.members(['AuthMixin.brs', 'testExtension4.brs']);
});
});
describe('build time imports', function () {
var _this = this;
beforeEach(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
Feedback_2.resetFeedback();
return [2 /*return*/];
});
}); });
it('adds build time imports', function () {
var file = createFile('components/screens/imports/build-time', '.bs');
file.setFileContents("import \"pkg:/source/mixins/FocusMixin.bs\"\nimport \"build:/IAuthProvider\"\n\nfunction Init() as void\n m.log.I(\"Init\")\n m.screenStack = createObject(\"roArray\", 0, true)\n m.top.topScreen = invalid\nend function");
importProcessor.parseFileImports(file);
chai_1.expect(__spread(file.importedPaths.values())).to.have.lengthOf(2);
chai_1.expect(__spread(file.importedPaths.values())).to.have.all.members([
'source/mixins/focusmixin.brs',
'source/mixins/netmixin.brs'
]);
chai_1.expect(Feedback_1.getFeedbackErrors()).to.be.empty;
});
it('throws error when a build time import is encountered, with no matching key in the config', function () {
var file = processor.fileMap.getFileByPkgPath('components/screens/imports/build-time.bs');
processor.config.buildTimeImports = null;
chai_1.expect(function () { return importProcessor.parseFileImports(file); }).to.throw(Error);
});
});
});
function createFile(path, extension) {
return new File_1.File(config.outputPath, path, "test" + extension, '.extension');
}
function getXMLScriptImportNamesFromFile(file) {
var regex = new RegExp('<.*?script.*uri=\\"(.*)\\".*\\/?>', 'gi');
return Utils_1.getRegexMatchesValues(file.getFileContents(), regex, 1)
.map(function (t) { return path.basename(t); });
}