File size: 8,762 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const iconv_corefoundation_1 = require("iconv-corefoundation");
const smart_buffer_1 = require("smart-buffer");
const Context_1 = require("./Context");
const util_1 = require("./util");
const errors_1 = require("./util/errors");
const format_verror_1 = require("./util/format-verror");
const PromiseEach_1 = require("./util/PromiseEach");
const { freeze } = Object;
class NoDefaultLabelsError extends Error {
    constructor(lang, message) {
        super(message || `There are no default labels for ${lang.englishName}. You must provide your own labels for this language.`);
        this.lang = lang;
    }
}
exports.NoDefaultLabelsError = NoDefaultLabelsError;
NoDefaultLabelsError.prototype.name = NoDefaultLabelsError.name;
class LabelEncodingError extends format_verror_1.PrettyVError {
    constructor(labelDescription, lang, cause, ...params) {
        super({ cause: typeof cause === "string" ? undefined : cause }, `Cannot encode %s for %s${typeof cause === "string" ? "%s" : cause ? "" : "."}`, labelDescription, lang.englishName, typeof cause === "string" ? cause : undefined, ...params);
    }
}
exports.LabelEncodingError = LabelEncodingError;
LabelEncodingError.prototype.name = LabelEncodingError.name;
var Labels;
(function (Labels) {
    Labels.names = freeze(["languageName", "agree", "disagree", "print", "save", "message"]);
    Labels.descriptions = freeze({
        agree: "“Agree” button label",
        disagree: "“Disagree” button label",
        languageName: "Language name",
        message: "License agreement instructions text",
        print: "“Print” button label",
        save: "“Save” button label"
    });
    async function fromPromises(labels) {
        const labelPromises = [];
        const result = {};
        for (const key of Labels.names) {
            const p = labels[key];
            if (p) {
                labelPromises.push(p.then(label => {
                    result[key] = label;
                }));
            }
        }
        await PromiseEach_1.default(labelPromises);
        return result;
    }
    Labels.fromPromises = fromPromises;
    function mapAsync(labels, fun, options) {
        return fromPromises(map(labels, fun, options));
    }
    Labels.mapAsync = mapAsync;
    function map(labels, fun, { onNoLanguageName } = {}) {
        const result = {};
        Labels.forEach(labels, (label, key) => {
            result[key] = fun(label, key, labels);
        }, {
            onNoLanguageName: onNoLanguageName ? () => {
                result.languageName = onNoLanguageName();
            } : undefined
        });
        return result;
    }
    Labels.map = map;
    function forEach(labels, fun, { onNoLanguageName } = {}) {
        for (const name of Labels.names) {
            const label = labels[name];
            if (label === undefined && name === "languageName") {
                if (onNoLanguageName)
                    onNoLanguageName();
            }
            else
                fun(label, name, labels);
        }
    }
    Labels.forEach = forEach;
    function create(fun, { includeLanguageName = false } = {}) {
        const labels = {};
        Labels.names.forEach((key, index) => {
            if (includeLanguageName || key !== "languageName")
                labels[key] = fun(key, index);
        });
        return labels;
    }
    Labels.create = create;
    function createAsync(fun, options) {
        return fromPromises(create(fun, options));
    }
    Labels.createAsync = createAsync;
    /**
     * Prepares a label set for insertion into a disk image as a `STR#` resource.
     *
     * @remarks
     * Throws {@link LabelEncodingError} if there is a problem encoding some of the labels.
     *
     * Throws {@link verror#MultiError} if there is more than one error.
     *
     * @param labels - The label set to prepare.
     *
     * @param lang - The language to prepare the label set for. This determines the target character set.
     *
     * @returns A `Buffer` in `STR#` format.
     */
    function prepare(labels, lang) {
        const sbuf = new smart_buffer_1.SmartBuffer();
        function writeStr(string, description, isDefaultLanguageName = false) {
            let data;
            try {
                data = lang.charset.encode(string);
            }
            catch (e) {
                errors.add(isDefaultLanguageName && e instanceof iconv_corefoundation_1.NotRepresentableError ?
                    new NoDefaultLabelsError(lang, `The default languageName label for ${lang.englishName}, “${lang.localizedName}”, is not representable in ${lang.charset}, the native character set for that language. Please provide a languageName label for this language that is representable in that character set.`) :
                    new LabelEncodingError(description, lang, e));
                return;
            }
            const length = data.length;
            if (length > 255) {
                const e = new LabelEncodingError(description, lang, "the label is too large to write into a STR# resource. The maximum size is 255 bytes, but it is %d bytes.", length);
                e.text = data;
                errors.add(e);
                return;
            }
            if (errors.isEmpty) {
                sbuf.writeUInt8(length);
                sbuf.writeBuffer(data);
            }
        }
        // Magic
        sbuf.writeUInt16BE(6);
        // Labels
        const errors = new errors_1.ErrorBuffer();
        Labels.forEach(labels, (label, key) => writeStr(label, Labels.descriptions[key]), { onNoLanguageName() {
                // If no language name is provided, try the languageName in the built-in labels, or failing that, the language's localizedName.
                writeStr(lang.labels && lang.labels.languageName || lang.localizedName, Labels.descriptions.languageName, true);
            } });
        errors.check();
        return sbuf.toBuffer();
    }
    Labels.prepare = prepare;
    /**
     * Prepares the given language's default label set for insertion into a disk image as a `STR#` resource.
     *
     * @remarks
     * Throws {@link NoDefaultLabelsError} if there is no default label set for the given language.
     *
     * Throws {@link LabelEncodingError} if there is a problem encoding some of the labels.
     *
     * Throws a {@link verror#MultiError} if there is more than one error.
     *
     * @param lang - The language to prepare the label set for.
     *
     * @param contextOrOptions - Context of an existing {@link dmgLicense} run, or options for one (when calling this function standalone).
     *
     * @returns A `Buffer` in `STR#` format.
     */
    function prepareDefault(lang) {
        const labels = lang.labels;
        if (!labels)
            throw new NoDefaultLabelsError(lang);
        return Labels.prepare(labels, lang);
    }
    Labels.prepareDefault = prepareDefault;
    /**
     * Prepares a label set for insertion into a disk image as a `STR#` resource.
     *
     * @remarks
     * This function delegates to `prepareDefault` or `prepare` as appropriate.
     *
     * Throws {@link NoDefaultLabelsError} if `labels` is `null` or `undefined` and there is no default label set for the given language.
     *
     * Throws {@link LabelEncodingError} if there is a problem encoding some of the labels.
     *
     * Throws a {@link verror#MultiError} if there is more than one error.
     *
     * @param labels - An object describing the label set to prepare. If `null` or `undefined`, the default label set for the given language is used instead.
     *
     * @param lang - The language to prepare the label set for. This determines the target character set, and if `labels` is `null` or `undefined`, which language's default label set to use.
     *
     * @param contextOrOptions - Context of an existing {@link dmgLicense} run, or options for one (when calling this function standalone). Used to resolve relative paths if `labels` is a `LabelsSpec.LabelsRaw`.
     *
     * @returns A `Buffer` in `STR#` format.
     */
    async function prepareSpec(labels, lang, contextOrOptions) {
        if (!labels)
            return prepareDefault(lang);
        else if (labels.file) {
            const context = Context_1.default.from(contextOrOptions);
            return util_1.readFileP(context.resolvePath(labels.file));
        }
        else
            return prepare(labels, lang);
    }
    Labels.prepareSpec = prepareSpec;
})(Labels = exports.Labels || (exports.Labels = {}));
Object.defineProperty(Labels, Symbol.toStringTag, { value: "Labels" });
exports.default = Labels;
//# sourceMappingURL=Labels.js.map