"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