tc-source-content-updater
Version:
Module that updates source content for the desktop application translationCore.
774 lines (683 loc) • 28.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getLocalResourceList = exports.getReleaseMetaData = exports.getLatestRelease = exports.downloadManifestData = exports.searchCatalogNext = exports.getCatalog = exports.getOldCatalogReleases = exports.doMultipartQuery = exports.doMultipartQueryPage = exports.makeJsonRequestDetailed = exports.DCS_BASE_URL = exports.SEARCH_LIMIT = exports.OWNER_SEPARATOR = exports.EMPTY_TIME = exports.TRANSLATION_HELPS = exports.DEFAULT_OWNER = exports.UNFOLDING_WORD = exports.CN_CATALOG = exports.DOOR43_CATALOG = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
/**
* does http request and returns the response data parsed from JSON
* @param {string} url
* @param {number} retries
* @return {Promise<{Object}>}
*/
let makeJsonRequestDetailed = exports.makeJsonRequestDetailed = (() => {
var _ref = _asyncToGenerator(function* (url, retries = 5) {
let result_;
for (let i = 1; i <= retries; i++) {
result_ = null;
try {
result_ = yield new Promise(function (resolve, reject) {
request(url, function (error, response, body) {
if (error) reject(error);else if (response.statusCode === 200) {
let result = body;
try {
result = JSON.parse(body);
} catch (e) {
reject(e);
}
resolve({ result, response, body });
} else {
reject(`fetch error ${response.statusCode}`);
}
});
});
} catch (e) {
if (i >= retries) {
console.warn(`makeJsonRequestDetailed(${url}) - error getting data`, e);
throw e;
}
result_ = null;
console.log(`makeJsonRequestDetailed(${url}) - retry ${i + 1} getting data, last error`, e);
yield (0, _utils.delay)(500);
}
if (result_) {
break;
}
}
return result_;
});
return function makeJsonRequestDetailed(_x) {
return _ref.apply(this, arguments);
};
})();
/**
* does specific page query and returns the response data parsed from JSON
* @param {string} url
* @param {number} page
* @param {number} retries
* @return {Promise<{Object}>}
*/
let doMultipartQueryPage = exports.doMultipartQueryPage = (() => {
var _ref2 = _asyncToGenerator(function* (url, page = 1, retries = 5) {
const url_ = `${url}&page=${page}`;
const { result, response } = yield makeJsonRequestDetailed(url_, retries);
const pos = response && response.rawHeaders && response.rawHeaders.indexOf('X-Total-Count');
const totalCount = pos >= 0 ? parseInt(response.rawHeaders[pos + 1]) : 0;
const items = result && result.data || null;
return { items, totalCount };
});
return function doMultipartQueryPage(_x2) {
return _ref2.apply(this, arguments);
};
})();
/**
* does multipart query and returns the response data parsed from JSON. Continues to read pages until all results are returned.
* @param {string} url
* @param {number} retries
* @return {Promise<{Object}>}
*/
let doMultipartQuery = exports.doMultipartQuery = (() => {
var _ref3 = _asyncToGenerator(function* (url, retries = 5) {
let page = 1;
let data = [];
const { items, totalCount } = yield doMultipartQueryPage(url, page, retries = 5);
let lastItems = items;
let totalCount_ = totalCount;
data = data.concat(items);
while (lastItems && data.length < totalCount_) {
const { items, totalCount } = yield doMultipartQueryPage(url, ++page, retries = 5);
lastItems = items;
totalCount_ = totalCount;
if (items && items.length) {
data = data.concat(items);
}
}
return data;
});
return function doMultipartQuery(_x3) {
return _ref3.apply(this, arguments);
};
})();
/**
* searching subjects
* @param {array} subjects
* @param {string} owner
* @param {number} retries
* @return {Promise<*>}
*/
let searchSubjects = (() => {
var _ref4 = _asyncToGenerator(function* (subjects, owner, retries = 3) {
const subjectParam = encodeURI(subjects.join(','));
let fetchUrl = `${DCS_BASE_URL}/api/v1/catalog/search?metadataType=rc&partialMatch=0&subject=${subjectParam}`;
if (owner) {
fetchUrl += fetchUrl + `&owner=${owner}`;
}
const result = yield doMultipartQuery(fetchUrl, retries);
return result;
});
return function searchSubjects(_x4, _x5) {
return _ref4.apply(this, arguments);
};
})();
/**
* get published catalog using catalog next v3
* @return {Promise<*[]>}
*/
let getOldCatalogReleases = exports.getOldCatalogReleases = (() => {
var _ref5 = _asyncToGenerator(function* () {
const released = [];
const owner = null; // get all owners
const subjectList = ['Bible', 'Aligned Bible', 'Greek New Testament', 'Hebrew Old Testament', 'Translation Words', 'TSV Translation Notes', 'Translation Academy'];
// const subjectList = ['Bible', 'Testament', 'Translation Words', 'TSV Translation Notes', 'Translation Academy'];
try {
const result = yield searchSubjects(subjectList, owner, 5);
let repos = 0;
const languages = result && result.languages || [];
for (const language of languages) {
const languageId = language.identifier;
const resources = language.resources || [];
for (const resource of resources) {
resource.languageId = languageId;
resource.resourceId = resource.identifier;
resource.foundInCatalog = 'OLD';
resource.full_name = resource.full_name || `${resource.owner}/${resource.repo}`;
resource.checking_level = resource.checking && resource.checking.checking_level;
const formats = resource.formats;
if (formats && formats.length > 1) {
console.log('too many');
}
const firstFormat = formats && formats[0];
resource.downloadUrl = firstFormat && firstFormat.url;
released.push(resource);
repos++;
}
}
console.log(`has ${repos} items`);
console.log(`released catalog has ${released.length} items`);
} catch (e) {
console.error('getOldCatalogReleases() - error getting catalog', e);
return [];
}
return released;
});
return function getOldCatalogReleases() {
return _ref5.apply(this, arguments);
};
})();
/**
* find matching resource in resourceList
* @param {array} resourceList
* @param {object} resource
* @return {*}
*/
/**
* get published catalog - combines catalog next releases with old catalog
* @param {object} config
* @param {string|null} config.stage - stage for search, default is prod
* @return {Promise<*[]>}
*/
let getCatalog = exports.getCatalog = (() => {
var _ref6 = _asyncToGenerator(function* (config = {}) {
let searchParams = {
subject: _index.SUBJECT.ALL_TC_RESOURCES,
stage: _index.STAGE.LATEST,
owner: DOOR43_CATALOG,
DCS_BASE_URL: config.DCS_BASE_URL,
partialMatch: '0'
};
const fetchDoor43Catalog = !config.ignoreDoor43Catalog;
const catalogReleases = fetchDoor43Catalog ? yield searchCatalogNext(searchParams) : [];
console.log(`getCatalog - found ${catalogReleases.length} items in old Door43-Catalog`);
searchParams = {
subject: _index.SUBJECT.ALL_TC_RESOURCES,
stage: config.stage || _index.STAGE.PROD,
DCS_BASE_URL: config.DCS_BASE_URL,
partialMatch: '0',
ignoreDoor43Catalog: config.ignoreDoor43Catalog,
topic: config.topic
};
const newCatalogReleases = yield searchCatalogNext(searchParams);
console.log(`getCatalog - found ${newCatalogReleases.length} items in catalog next`);
let catalogReleases_ = filterOutMasterBranch(catalogReleases, ['obs', 'obs-tn'], newCatalogReleases);
console.log(`getCatalog - found ${catalogReleases_.length} items in old Door43-Catalog after filter`);
const newCatalogReleases_ = filterOutMasterBranch(newCatalogReleases, ['obs', 'obs-tn']);
console.log(`getCatalog - found ${newCatalogReleases_.length} items in catalog next after filter`);
// merge catalogs together - catalog new takes precedence
for (const item of newCatalogReleases_) {
const index = catalogReleases_.findIndex(function (oldItem) {
return item.full_name === oldItem.full_name && item.full_name === oldItem.full_name;
});
if (index >= 0) {
catalogReleases_[index] = item; // overwrite item in old catalog
catalogReleases_[index].foundInCatalog = 'NEW+OLD';
} else {
catalogReleases_.push(item); // add unique item
}
}
console.log(`getCatalog - now ${catalogReleases_.length} items in merged catalog, before filter`);
// combine tw and twl dependencies
catalogReleases_ = combineTwords(catalogReleases_);
console.log(`getCatalog - now ${catalogReleases_.length} items in filtered catalog`);
return catalogReleases_;
});
return function getCatalog() {
return _ref6.apply(this, arguments);
};
})();
/**
* add parameter to url string
* @param {*} value
* @param {object} parameters
* @param {string} tag
* @return {*}
*/
/**
* @typedef {Object} searchParamsType
* @property {String} owner - resource owner, if undefined then all are searched
* @property {String} languageId - language of resource, if undefined then all are searched
* @property {String} subject - one or more subjects separated by comma. See options defined in SUBJECT.
* If undefined then all are searched.
* @property {Number} limit - maximum results to return, default 100
* @property {String} partialMatch - if true will do case insensitive, substring matching, default is false
* @property {String} stage - specifies which release stage to be returned out of these stages:
* STAGE.PROD - return only the production releases
* STAGE.PRE_PROD - return the pre-production release if it exists instead of the production release
* STAGE.DRAFT - return the draft release if it exists instead of pre-production or production release
* STAGE.LATEST -return the default branch (e.g. master) if it is a valid RC instead of the "prod", "preprod" or "draft". (default)
* @property {Number|String} checkingLevel - search only for entries with the given checking level(s). Can be 1, 2 or 3. Default is any.
* @property {String} sort - how to sort results (see defines in SORT), if undefined then sorted by by "lang", then "subject" and then "tag"
* @property {String|String[]} topic - filter by topic tags (e.g. "tc-ready")
*/
/**
* Method to search for latest resources using catalog next
* @param {searchParamsType} searchParams - search options
* @param {number} retries - number of times to retry calling search API, default 3
* @return {Promise<*[]|null>}
*/
let searchCatalogNext = exports.searchCatalogNext = (() => {
var _ref7 = _asyncToGenerator(function* (searchParams, retries = 3) {
let result_ = null;
const start = Date.now();
const {
owner,
languageId,
subject,
limit = SEARCH_LIMIT,
stage = _index.STAGE.LATEST,
checkingLevel,
partialMatch,
sort = _index.SORT.REPO_NAME,
DCS_BASE_URL: baseUrl = DCS_BASE_URL,
topic
} = searchParams;
try {
let fetchUrl = `${baseUrl}/api/v1/catalog/search`;
let parameters = '';
parameters = addUrlParameter(owner, parameters, 'owner');
parameters = addUrlParameter(languageId, parameters, 'lang');
parameters = addUrlParameter(subject, parameters, 'subject');
parameters = addUrlParameter(limit, parameters, 'limit');
parameters = addUrlParameter(stage, parameters, 'stage');
parameters = addUrlParameter(checkingLevel, parameters, 'checkingLevel');
parameters = addUrlParameter(partialMatch, parameters, 'partialMatch');
parameters = addUrlParameter('rc', parameters, 'metadataType');
parameters = addUrlParameter(sort, parameters, 'sort');
if (Array.isArray(topic)) {
for (const topicItem of topic) {
{
parameters = addUrlParameter(topicItem, parameters, 'topic');
}
}
} else {
parameters = addUrlParameter(topic, parameters, 'topic');
}
if (parameters) {
fetchUrl += '?' + parameters;
}
console.log(`Searching: ${fetchUrl}`);
result_ = yield doMultipartQuery(fetchUrl, retries);
const end = Date.now();
const elapsed = (end - start) / (60 * 1000); // Convert milliseconds to minutes
console.log(`searchCatalogNext() - search took: ${elapsed} minutes`);
} catch (e) {
console.warn('searchCatalogNext() - error calling search API', e);
return null;
}
const supported = getCompatibleResourceList(result_);
return supported;
});
return function searchCatalogNext(_x6) {
return _ref7.apply(this, arguments);
};
})();
/**
* does Catalog next API query to get manifest data
* @param {string} owner
* @param {string} repo
* @param {string} tag
* @param {number} retries
* @param {string} baseUrl - optional server to use
* @return {Promise<{Object}>}
*/
let downloadManifestData = exports.downloadManifestData = (() => {
var _ref8 = _asyncToGenerator(function* ({ owner, repo, tag = 'master', retries = 5, baseUrl = DCS_BASE_URL }) {
const fetchUrl = `${baseUrl}/api/v1/catalog/entry/${owner}/${repo}/${tag}/metadata`;
try {
const { result } = yield makeJsonRequestDetailed(fetchUrl, retries);
return result;
} catch (e) {
console.warn('downloadManifestData() - error getting manifest data', e);
throw e;
}
});
return function downloadManifestData(_x7) {
return _ref8.apply(this, arguments);
};
})();
/**
* does Catalog next API query to get metadata for latest version
* @param {string} owner
* @param {string} repo
* @param {number} retries
* @param {string} stage - null defaults to production
* @param {string} baseUrl - optional server to use
* @return {Promise<{Object}>}
*/
let getLatestRelease = exports.getLatestRelease = (() => {
var _ref9 = _asyncToGenerator(function* ({ owner, repo, retries = 5, stage = null, baseUrl = DCS_BASE_URL }) {
let fetchUrl = `${baseUrl}/api/v1/catalog/search/${owner}/${repo}`;
if (stage) {
fetchUrl += `?stage=${stage}`;
}
try {
const { result } = yield makeJsonRequestDetailed(fetchUrl, retries);
if (result.data[0] && result.data[0].release) {
return result.data[0];
}
console.warn(`getLatestRelease() - error getting release data, empty response to ${fetchUrl}`);
return null;
} catch (e) {
console.warn(`getLatestRelease() - error getting release data from ${fetchUrl}`, e);
throw e;
}
});
return function getLatestRelease(_x8) {
return _ref9.apply(this, arguments);
};
})();
/**
* does Catalog next API query to get metadata for tag
* @param {string} owner
* @param {string} repo
* @param {string|null} tag
* @param {number} retries
* @param {string} baseUrl - optional server to use
* @return {Promise<{Object}>}
*/
let getReleaseMetaData = exports.getReleaseMetaData = (() => {
var _ref10 = _asyncToGenerator(function* ({ owner, repo, tag, retries = 5, baseUrl = DCS_BASE_URL }) {
const fetchUrl = `${baseUrl}/api/v1/catalog/entry/${owner}/${repo}/${tag}`;
try {
const { result } = yield makeJsonRequestDetailed(fetchUrl, retries);
return result;
} catch (e) {
console.warn('getReleaseMetaData() - error getting manifest data', e);
throw e;
}
});
return function getReleaseMetaData(_x9) {
return _ref10.apply(this, arguments);
};
})();
/**
* reads Json file if it exists, otherwise returns null
* @param {string} jsonPath
* @return {object|null}
*/
exports.combineTwords = combineTwords;
exports.readJsonFile = readJsonFile;
exports.getOwnerForOriginalLanguage = getOwnerForOriginalLanguage;
exports.formatVersionWithV = formatVersionWithV;
exports.formatVersionWithoutV = formatVersionWithoutV;
var _utils = require('./utils');
var _index = require('../index');
var _fsExtra = require('fs-extra');
var _fsExtra2 = _interopRequireDefault(_fsExtra);
var _pathExtra = require('path-extra');
var _pathExtra2 = _interopRequireDefault(_pathExtra);
var _bible = require('../resources/bible');
var Bible = _interopRequireWildcard(_bible);
var _resourcesHelpers = require('./resourcesHelpers');
var _parseHelpers = require('./parseHelpers');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
const request = require('request');
const DOOR43_CATALOG = exports.DOOR43_CATALOG = `Door43-Catalog`;
const CN_CATALOG = exports.CN_CATALOG = `unfoldingWord`;
const UNFOLDING_WORD = exports.UNFOLDING_WORD = `unfoldingWord`;
const DEFAULT_OWNER = exports.DEFAULT_OWNER = DOOR43_CATALOG;
const TRANSLATION_HELPS = exports.TRANSLATION_HELPS = 'translationHelps';
const EMPTY_TIME = exports.EMPTY_TIME = '0001-01-01T00:00:00+00:00';
const OWNER_SEPARATOR = exports.OWNER_SEPARATOR = '_';
const SEARCH_LIMIT = exports.SEARCH_LIMIT = 250;
const DCS_BASE_URL = exports.DCS_BASE_URL = 'https://git.door43.org';function findResource(resourceList, resource) {
const foundResource = resourceList.find(item => {
return item.owner === resource.owner && item.language === resource.language && item.resourceId === resource.resourceId;
});
return foundResource;
}
/**
* merge twl resource downloads into tw downloads
* @param {Array} catalogReleases
* @return {*}
*/
function combineTwords(catalogReleases) {
return catalogReleases.filter(resource => {
if (resource.owner !== 'Door43-Catalog') {
switch (resource.resourceId) {
case 'twl':
{
const twResource = findResource(catalogReleases, _extends({}, resource, { resourceId: 'tw' }));
if (twResource) {
twResource.loadAfter = [resource];
} else {
return false; // if no tw available, we cannot use the twl
}
break;
}
case 'tw':
{
const twlResource = findResource(catalogReleases, _extends({}, resource, { resourceId: 'twl' }));
if (twlResource) {
resource.loadAfter = [twlResource];
} else {
return false; // if no twl available, we cannot use the tw
}
}
break;
}
}
return true;
});
}
/**
* check if tag name is valid for release version
* @param {string} tagName
* @return {boolean}
*/
function isValidVersionTag(tagName) {
const firstChar = tagName && tagName[0];
const isDigit = firstChar >= '0' && firstChar <= '9';
const isValidVersionTag = firstChar && (firstChar === 'v' || isDigit);
return isValidVersionTag;
}
/**
* filter list of items and ignore master branch
* @param {[object]} catalog - array of resources
* @param {[string]} ignoredResources
* @param {[object]} newCatalog - new catalog to search for matches to Door43-Catalog matches in unfoldingWord
* @return {[object]}
*/
function filterOutMasterBranch(catalog, ignoredResources = [], newCatalog = []) {
let catalog_ = catalog.filter(resource => {
if (ignoredResources.includes(resource.resource)) {
return false; // reject ignored resources
}
const tagName = resource.branch_or_tag_name;
if (tagName) {
// check for version
const _isValidVersionTag = isValidVersionTag(tagName);
const isD43Master = tagName === 'master' && resource.owner === DOOR43_CATALOG;
if (isD43Master) {
// find the latest release in unfoldingWord org to get version info
const sourceResource = findResource(newCatalog, _extends({}, resource, { owner: UNFOLDING_WORD }));
if (sourceResource) {
const _tagName = sourceResource.branch_or_tag_name;
if (isValidVersionTag(_tagName)) {
// copy latest release data from source
resource.branch_or_tag_name = _tagName;
resource.released = sourceResource.released;
resource.modified = sourceResource.modified;
resource.zipball_url = sourceResource.zipball_url;
resource.downloadUrl = sourceResource.downloadUrl;
return true;
}
}
} else if (_isValidVersionTag) {
return true;
}
console.log(`filterOutMasterBranch - invalid version: ${tagName} in ${(0, _parseHelpers.getResourceInfo)(resource)}`);
return false; // reject if tag is not a version
}
return true;
});
return catalog_;
}function addUrlParameter(value, parameters, tag) {
if (value) {
if (parameters) {
// see if we need separator
parameters += '&';
}
parameters += `${tag}=${encodeURIComponent(value)}`;
}
return parameters;
}
/**
* filter for supported repos
* @param {array} resources
* @return {*[]}
*/
function getCompatibleResourceList(resources) {
const supported = [];
for (const item of resources || []) {
// add fields for backward compatibility
const languageId = item.language;
let [, resourceId] = (item.name || '').split(`${languageId}_`);
resourceId = resourceId || item.name; // if language was not in name, then use name as resource ID
item.resourceId = resourceId;
item.languageId = languageId;
item.checking_level = item.repo && item.repo.checking_level;
item.foundInCatalog = 'NEW';
item.modified = item.modified || item.released;
if (item.zipball_url) {
item.downloadUrl = item.zipball_url;
}
// check for version. if there is one, it will save having to fetch it from DCS later.
if (item.release) {
// if released
const tagName = item.release.tag_name;
if (tagName && tagName[0] === 'v') {
item.version = tagName.substr(1);
}
} else {
const branchOrTagName = item.branch_or_tag_name;
if (branchOrTagName && branchOrTagName[0] === 'v') {
item.version = branchOrTagName.substr(1);
}
}
if (item.subject) {
item.subject = item.subject.replaceAll(' ', '_');
}
// add supported resources to returned list
if (item.downloadUrl && item.subject && item.name && item.full_name) {
supported.push(item);
}
}
return supported;
}function readJsonFile(jsonPath) {
if (_fsExtra2.default.existsSync(jsonPath)) {
try {
const resourceManifest = _fsExtra2.default.readJsonSync(jsonPath);
return resourceManifest;
} catch (e) {
console.error(`getLocalResourceList(): could not read ${jsonPath}`, e);
}
}
return null;
}
/**
* add resource to list
* @param {string} resourceLatestPath
* @param {string} pathToResourceManifestFile
* @param {string} languageId
* @param {string} resourceId
* @param {array} localResourceList
*/
function addLocalResource(resourceLatestPath, pathToResourceManifestFile, languageId, resourceId, localResourceList) {
const { version, owner } = (0, _resourcesHelpers.getVersionAndOwnerFromPath)(resourceLatestPath);
const resourceManifest = readJsonFile(pathToResourceManifestFile);
if (resourceManifest) {
const localResource = {
languageId,
resourceId,
owner,
version,
modifiedTime: resourceManifest.catalog_modified_time,
manifest: resourceManifest
};
localResourceList.push(localResource);
} else {
console.log(`addLocalResource(): no such file or directory, ${pathToResourceManifestFile}`);
}
}
/**
* get local resources
* @param {string} resourcesPath
* @return {null|*[]}
*/
const getLocalResourceList = exports.getLocalResourceList = resourcesPath => {
try {
if (!_fsExtra2.default.existsSync(resourcesPath)) {
_fsExtra2.default.ensureDirSync(resourcesPath);
}
const localResourceList = [];
const resourceLanguages = _fsExtra2.default.readdirSync(resourcesPath).filter(file => _pathExtra2.default.extname(file) !== '.json' && file !== '.DS_Store');
for (let i = 0; i < resourceLanguages.length; i++) {
const languageId = resourceLanguages[i];
const biblesPath = _pathExtra2.default.join(resourcesPath, languageId, 'bibles');
const tHelpsPath = _pathExtra2.default.join(resourcesPath, languageId, TRANSLATION_HELPS);
const bibleIds = (0, _resourcesHelpers.cleanReaddirSync)(biblesPath);
const tHelpsResources = (0, _resourcesHelpers.cleanReaddirSync)(tHelpsPath);
bibleIds.forEach(bibleId => {
const bibleIdPath = _pathExtra2.default.join(biblesPath, bibleId);
const owners = (0, _resourcesHelpers.getLatestVersionsAndOwners)(bibleIdPath) || {};
for (const owner of Object.keys(owners)) {
const bibleLatestVersion = owners[owner];
if (bibleLatestVersion) {
const pathToBibleManifestFile = _pathExtra2.default.join(bibleLatestVersion, 'manifest.json');
addLocalResource(bibleLatestVersion, pathToBibleManifestFile, languageId, bibleId, localResourceList);
} else {
console.log(`getLocalResourceList(): bibleLatestVersion is not found.`);
}
}
});
tHelpsResources.forEach(tHelpsId => {
const tHelpResource = _pathExtra2.default.join(tHelpsPath, tHelpsId);
const latestVersions = (0, _resourcesHelpers.getLatestVersionsAndOwners)(tHelpResource) || {};
const resourceId = _parseHelpers.RESOURCE_ID_MAP[tHelpsId] || tHelpsId; // map resource names to ids
for (const owner of Object.keys(latestVersions)) {
const tHelpsLatestVersion = latestVersions[owner];
if (tHelpsLatestVersion) {
const pathTotHelpsManifestFile = _pathExtra2.default.join(tHelpsLatestVersion, 'manifest.json');
addLocalResource(tHelpsLatestVersion, pathTotHelpsManifestFile, languageId, resourceId, localResourceList);
} else {
console.log(`getLocalResourceList(): tHelpsLatestVersion is ${tHelpsLatestVersion}.`);
}
}
});
}
return localResourceList;
} catch (error) {
console.error(error);
return null;
}
};
/**
* determine owner for original language resource. If resource owner is door43 Catalog, then the original
* language resource will be the same. Otherwise it will be unfoldingWord.
* @param {string} resourceOwner
* @return {string}
*/
function getOwnerForOriginalLanguage(resourceOwner) {
const origLangOwner = resourceOwner !== DOOR43_CATALOG ? CN_CATALOG : DOOR43_CATALOG;
return origLangOwner;
}
/**
* make sure version starts with v
* @param {string} version
* @return {string}
*/
function formatVersionWithV(version) {
const version_ = version[0] === 'v' ? version : 'v' + version;
return version_;
}
/**
* make sure version does not start with v
* @param {string} version
* @return {string}
*/
function formatVersionWithoutV(version) {
const version_ = version[0] === 'v' ? version.substring(1) : version;
return version_;
}