File size: 5,488 Bytes
e4a10af
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"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) {
    // Use the configured default language, if available.
    {
        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;
        }
    }
    // Use the first language of the first license body section.
    for (const body of spec.body)
        for (const lang of Language_1.default.bySpec(body.lang))
            return lang.languageID;
    // Just pick one arbitrarily. This should never happen, but just in case.
    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;
//# sourceMappingURL=assembleLicenses.js.map