|
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
const crc_1 = require("crc"); |
|
const _1 = require("."); |
|
const Context_1 = require("./Context"); |
|
const Labels_1 = require("./Labels"); |
|
const Language_1 = require("./Language"); |
|
const errors_1 = require("./util/errors"); |
|
const PromiseEach_1 = require("./util/PromiseEach"); |
|
function warnAboutLanguageIDCollisions(kind, errors, context) { |
|
return (languageIDs) => { |
|
const plural = languageIDs.size !== 1; |
|
context.warning(new Error(`More than one ${kind} was assigned to the language${plural ? "s" : ""} ${Array.from(languageIDs) |
|
.map(languageID => { |
|
const language = Language_1.default.byID[languageID]; |
|
return `${language.englishName} (${language.langTags.join("; ")})`; |
|
}) |
|
.join(", ")}. ${plural ? "In each case, t" : "T"}he first applicable ${kind} has been used.`), errors); |
|
}; |
|
} |
|
function hashAssembledLicense(content) { |
|
return [content.body.type, content.body.data, content.labels].reduce((hash, next) => crc_1.crc32(next, hash), 0); |
|
} |
|
function assembledLicensesEqual(a, b) { |
|
return a.body.type === b.body.type |
|
&& a.body.data.equals(b.body.data) |
|
&& a.labels.equals(b.labels); |
|
} |
|
async function assembleLoadedLicenses(bodies, labelSets, errors, context) { |
|
const assembled = new Map(); |
|
for (const [languageID, bodyPromise] of bodies) { |
|
try { |
|
const [body, labels] = await PromiseEach_1.default([ |
|
bodyPromise, |
|
labelSets(Language_1.default.byID[languageID]) |
|
]); |
|
assembled.set(languageID, { |
|
body, |
|
labels, |
|
languageIDs: [languageID] |
|
}); |
|
} |
|
catch (e) { |
|
errors.add(e); |
|
} |
|
} |
|
const hashes = new Map(); |
|
for (const license of assembled.values()) { |
|
const hash = hashAssembledLicense(license); |
|
const withThisHash = hashes.get(hash); |
|
if (!withThisHash) |
|
hashes.set(hash, [license]); |
|
else { |
|
let hashCollision = true; |
|
for (const other of withThisHash) |
|
if (assembledLicensesEqual(license, other)) { |
|
hashCollision = false; |
|
other.languageIDs.push(...license.languageIDs); |
|
for (const languageID of license.languageIDs) |
|
assembled.set(languageID, other); |
|
break; |
|
} |
|
if (hashCollision) |
|
withThisHash.push(license); |
|
} |
|
} |
|
return assembled; |
|
} |
|
function chooseDefaultLanguageID(spec, outputs, context) { |
|
|
|
{ |
|
const configuredDefaultLanguage = spec.defaultLang; |
|
switch (typeof configuredDefaultLanguage) { |
|
case "number": |
|
return configuredDefaultLanguage; |
|
case "string": |
|
const lookup = Language_1.default.bySpec(configuredDefaultLanguage, context)[0]; |
|
if (lookup) |
|
return lookup.languageID; |
|
} |
|
} |
|
|
|
for (const body of spec.body) |
|
for (const lang of Language_1.default.bySpec(body.lang)) |
|
return lang.languageID; |
|
|
|
for (const output of outputs) |
|
for (const lang of output.languageIDs) |
|
return lang; |
|
} |
|
function labelCache(spec, errors, context) { |
|
const labelSpecs = Language_1.indexByLanguage(function* () { |
|
const { labels, rawLabels } = spec; |
|
if (labels) |
|
for (const label of labels) |
|
yield label; |
|
if (rawLabels) |
|
for (const label of rawLabels) |
|
yield label; |
|
}(), { |
|
onCollisions: warnAboutLanguageIDCollisions("label set", errors, context) |
|
}); |
|
const preparedCache = new Map(); |
|
return (lang) => { |
|
const { languageID } = lang; |
|
let result = preparedCache.get(languageID); |
|
if (!result) { |
|
result = Labels_1.default.prepareSpec(labelSpecs.get(languageID), lang, context); |
|
preparedCache.set(languageID, result); |
|
} |
|
return result; |
|
}; |
|
} |
|
async function assembleLicenses(spec, optionsOrContext) { |
|
const context = optionsOrContext instanceof Context_1.default ? optionsOrContext : new Context_1.default(optionsOrContext); |
|
const errors = new errors_1.ErrorBuffer(); |
|
const labelSets = labelCache(spec, errors, context); |
|
const bodies = Language_1.indexByLanguage(spec.body, { |
|
map: (body, lang) => _1.BodySpec.prepare(body, lang, context), |
|
onCollisions: warnAboutLanguageIDCollisions("license body", errors, context) |
|
}); |
|
if (!bodies.size) |
|
errors.throw(new Error("No license bodies were provided.")); |
|
let result; |
|
try { |
|
const assembled = await assembleLoadedLicenses(bodies, labelSets, errors, context); |
|
const inOrder = Array.from(assembled.values()); |
|
const defaultLanguageID = chooseDefaultLanguageID(spec, inOrder, context); |
|
result = { |
|
byLanguageID: assembled, |
|
defaultLanguageID, |
|
inOrder |
|
}; |
|
} |
|
catch (e) { |
|
errors.add(e); |
|
} |
|
errors.check(); |
|
return result; |
|
} |
|
exports.default = assembleLicenses; |
|
|