fill-pot-po
Advanced tools
Comparing version
import Vinyl from 'vinyl'; | ||
import { Omit } from 'utility-types'; | ||
@@ -23,9 +24,26 @@ type Source = string | Vinyl; | ||
}; | ||
type StandardizedOptions = Omit<ValidatedOptions, 'potSources' | 'poSources'> & { | ||
potSources?: Source[]; | ||
poSources?: string[] | null; | ||
}; | ||
type PreparedOptions = Required<StandardizedOptions>; | ||
type AsyncCallbackResult = [true, Vinyl[]] | [false, string]; | ||
type AsyncCallback = (result: AsyncCallbackResult) => unknown; | ||
declare const _default$1: (cb: AsyncCallback, options: Options) => void; | ||
declare const _default$2: (cb: AsyncCallback, options: Options) => void; | ||
declare const _default: (options: Options) => Vinyl[]; | ||
declare const _default$1: (options: Options) => Vinyl[]; | ||
/** | ||
* Process user supplied options and merge with default options. | ||
* | ||
* @param {mixed} options | ||
* @param {boolean} writeFiles Default value for `options.writeFiles`. | ||
* | ||
* @throws OptionError on invalid, missing or incompatible options. | ||
* | ||
* @return {object} | ||
*/ | ||
declare const _default: (options: Options) => PreparedOptions; | ||
declare const testOptions: { | ||
@@ -39,2 +57,2 @@ wrapLength: number; | ||
export { _default$1 as default, _default as sync, testOptions }; | ||
export { _default$2 as default, _default as prepareOptions, _default$1 as sync, testOptions }; |
@@ -1,690 +0,4 @@ | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames(from)) | ||
if (!__hasOwnProp.call(to, key) && key !== except) | ||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
// If the importer is in node compatibility mode or this is not an ESM | ||
// file that has been converted to a CommonJS file using a Babel- | ||
// compatible transform (i.e. "__esModule" has not been set), then set | ||
// "default" to the CommonJS "module.exports" for node compatibility. | ||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
mod | ||
)); | ||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
// src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
default: () => async_default, | ||
sync: () => sync_default, | ||
testOptions: () => testOptions | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// node_modules/tsup/assets/cjs_shims.js | ||
var getImportMetaUrl = () => typeof document === "undefined" ? new URL("file:" + __filename).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href; | ||
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl(); | ||
// src/async.ts | ||
var fs = __toESM(require("fs")); | ||
var import_vinyl4 = __toESM(require("vinyl")); | ||
var import_safe_buffer2 = require("safe-buffer"); | ||
var import_gettext_parser2 = __toESM(require("gettext-parser")); | ||
var import_ansi_colors3 = __toESM(require("ansi-colors")); | ||
var import_color_support3 = __toESM(require("color-support")); | ||
// src/plugin-error.ts | ||
var util = __toESM(require("util")); | ||
var import_ansi_colors = __toESM(require("ansi-colors")); | ||
var import_color_support = __toESM(require("color-support")); | ||
var import_node_fs = require("fs"); | ||
import_ansi_colors.default.enabled = Boolean((0, import_color_support.default)().hasBasic); | ||
var packageJSON = JSON.parse( | ||
(0, import_node_fs.readFileSync)(new URL("../package.json", importMetaUrl), "utf-8") | ||
); | ||
var PluginError = class { | ||
message; | ||
category; | ||
constructor(message, category = "") { | ||
this.message = message; | ||
this.category = category.slice(0, 1).toUpperCase() + category.slice(1).toLowerCase(); | ||
} | ||
toString() { | ||
return `${import_ansi_colors.default.cyan(packageJSON.name)} ${import_ansi_colors.default.bold.red( | ||
`${this.category}Error` | ||
)} ${this.message}`; | ||
} | ||
// See: https://nodejs.org/api/util.html#custom-inspection-functions-on-objects | ||
[util.inspect.custom]() { | ||
return this.toString(); | ||
} | ||
}; | ||
var plugin_error_default = PluginError; | ||
// src/options.ts | ||
var import_node_path = require("path"); | ||
// src/utils.ts | ||
var import_vinyl = __toESM(require("vinyl")); | ||
var isArray = (value) => { | ||
return Object.prototype.toString.call(value) === "[object Array]"; | ||
}; | ||
var isObject = (value) => { | ||
return Object.prototype.toString.call(value) === "[object Object]"; | ||
}; | ||
var isString = (value) => { | ||
return Object.prototype.toString.call(value) === "[object String]"; | ||
}; | ||
var isBool = (value) => { | ||
return Object.prototype.toString.call(value) === "[object Boolean]"; | ||
}; | ||
var isVinyl = (value) => { | ||
return import_vinyl.default.isVinyl(value); | ||
}; | ||
var isArrayOfStrings = (value) => { | ||
if (!isArray(value)) | ||
return false; | ||
return Boolean( | ||
value.reduce((r, v) => isString(v) && r, true) | ||
); | ||
}; | ||
var isArrayOfVinyls = (value) => { | ||
if (!isArray(value)) | ||
return false; | ||
return Boolean(value.reduce((r, v) => isVinyl(v) && r, true)); | ||
}; | ||
var pathLineSort = (a, b) => { | ||
if (!isString(a) || !isString(b)) { | ||
throw new Error("pathLineSort: a or b not a string"); | ||
} | ||
let a_line, b_line; | ||
[a, a_line] = a.split(":"); | ||
[b, b_line] = b.split(":"); | ||
a = a.replace(/(^\/|\/$)/g, ""); | ||
b = b.replace(/(^\/|\/$)/g, ""); | ||
if (a === b) { | ||
if ((!a_line || "" === a_line) && b_line && b_line.length) | ||
return -1; | ||
if ((!b_line || "" === b_line) && a_line && a_line.length) | ||
return 1; | ||
if (a_line && a_line.length && b_line && b_line.length) { | ||
return parseInt(a_line) - parseInt(b_line); | ||
} | ||
} | ||
const a_ar = a.split("/"); | ||
const b_ar = b.split("/"); | ||
const a_len = a_ar.length; | ||
const b_len = b_ar.length; | ||
const l = Math.max(a_len, b_len); | ||
for (let i = 0; i < l; i++) { | ||
if (i >= b_len || !b_ar[i]) | ||
return -1; | ||
if (i >= a_len || !a_ar[i]) | ||
return 1; | ||
const [a_part, a_ext] = a_ar[i].split(/\.(?=[^.]*$)/g); | ||
const [b_part, b_ext] = b_ar[i].split(/\.(?=[^.]*$)/g); | ||
const a_is_file = a_ext && "" !== a_ext; | ||
const b_is_file = b_ext && "" !== b_ext; | ||
if (!a_is_file && b_is_file) | ||
return -1; | ||
if (a_is_file && !b_is_file) | ||
return 1; | ||
if (a_part.toUpperCase() > b_part.toUpperCase()) | ||
return 1; | ||
if (a_part.toUpperCase() < b_part.toUpperCase()) | ||
return -1; | ||
if (a_ext && b_ext) { | ||
if (a_ext.toUpperCase() > b_ext.toUpperCase()) | ||
return 1; | ||
if (a_ext.toUpperCase() < b_ext.toUpperCase()) | ||
return -1; | ||
} | ||
} | ||
return 0; | ||
}; | ||
// src/options.ts | ||
var import_vinyl2 = require("vinyl"); | ||
var OptionsError = class extends plugin_error_default { | ||
constructor(message) { | ||
super(message, "options"); | ||
} | ||
}; | ||
var cwd = "./"; | ||
var validateOptionsInput = (options) => { | ||
if (isObject(options)) { | ||
if ("potSources" in options && !isString(options.potSources) && !isArrayOfStrings(options.potSources) && // !Buffer.isBuffer(options.potSources) && | ||
// !isArrayOfBuffers(options.potSources) && | ||
// !isArrayOfVinylsOrBuffers(options.potSources) && | ||
!(0, import_vinyl2.isVinyl)(options.potSources) && !isArrayOfVinyls(options.potSources)) { | ||
throw new OptionsError( | ||
"Option potSources should be a string or Vinyl object, or an array of those." | ||
); | ||
} | ||
if ("poSources" in options && // options.poSources && | ||
options.poSources !== null && !isString(options.poSources) && !isArrayOfStrings(options.poSources)) { | ||
throw new OptionsError( | ||
"Option poSources should be a glob string or glob array." | ||
); | ||
} | ||
if ("wrapLength" in options && (typeof options.wrapLength !== "number" || 0 >= options.wrapLength)) { | ||
throw new OptionsError( | ||
"If set, option wrapLength should be a number higher than 0." | ||
); | ||
} | ||
const if_set_string_without_newlines = [ | ||
"srcDir", | ||
"destDir", | ||
"domain" | ||
]; | ||
for (const k of if_set_string_without_newlines) { | ||
if (k in options) { | ||
if (!isString(options[k])) { | ||
throw new OptionsError(`Option ${k} should be a string.`); | ||
} else if (options[k].match(/\n/)) { | ||
throw new OptionsError( | ||
`Option ${k} can't contain newline characters.` | ||
); | ||
} | ||
} | ||
} | ||
const if_set_bool = [ | ||
"writeFiles", | ||
"returnPOT", | ||
"domainFromPOTPath", | ||
"domainInPOPath", | ||
"defaultContextAsFallback", | ||
"appendNonIncludedFromPO", | ||
"includePORevisionDate", | ||
"includeGenerator", | ||
"logResults" | ||
]; | ||
for (const k of if_set_bool) { | ||
if (k in options && !isBool(options[k])) { | ||
throw new OptionsError(`Option ${k} should be a boolean.`); | ||
} | ||
} | ||
} else if (isString(options) || isArrayOfStrings(options)) { | ||
return { | ||
poSources: options | ||
}; | ||
} else if (typeof options !== "undefined") { | ||
throw new OptionsError( | ||
"Options should be an object of options, glob string or glob array." | ||
); | ||
} else { | ||
return {}; | ||
} | ||
return options; | ||
}; | ||
var sanitizeAndStandardizeOptionsInput = (options) => { | ||
if (typeof options.potSources !== "undefined") { | ||
if (!isArray(options.potSources)) { | ||
options.potSources = [options.potSources]; | ||
} | ||
options.potSources = options.potSources.map((v) => isString(v) ? v.trim() : v).filter((v) => !isString(v) || v.length > 0); | ||
} | ||
if (typeof options.poSources !== "undefined" && options.poSources !== null) { | ||
if (!isArray(options.poSources)) { | ||
options.poSources = [options.poSources]; | ||
} | ||
options.poSources = options.poSources.map((v) => v.trim()).filter((v) => v.length > 0); | ||
} | ||
if (options.srcDir) { | ||
options.srcDir = (0, import_node_path.resolve)(options.srcDir.trim()); | ||
options.srcDir = `${(0, import_node_path.relative)(cwd, options.srcDir)}/`.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/(?<!\.)\.\//g, "").replace(/^\//g, ""); | ||
} | ||
if (options.destDir) { | ||
options.destDir = (0, import_node_path.resolve)(options.destDir.trim()); | ||
options.destDir = `${(0, import_node_path.relative)(cwd, options.destDir)}/`.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/(?<!\.)\.\//g, "").replace(/^\//g, ""); | ||
} | ||
if (options.wrapLength) { | ||
options.wrapLength = Math.ceil(options.wrapLength); | ||
} | ||
return options; | ||
}; | ||
var options_default = (options) => { | ||
cwd = (0, import_node_path.resolve)(); | ||
options = validateOptionsInput(options); | ||
options = sanitizeAndStandardizeOptionsInput(options); | ||
const defaultOptions = { | ||
// Input-related | ||
potSources: ["**/*.pot", "!node_modules/**"], | ||
poSources: null, | ||
srcDir: "", | ||
domainInPOPath: true, | ||
domainFromPOTPath: true, | ||
domain: "", | ||
srcGlobOptions: {}, | ||
// Content-related | ||
wrapLength: 77, | ||
defaultContextAsFallback: false, | ||
appendNonIncludedFromPO: false, | ||
includePORevisionDate: false, | ||
includeGenerator: true, | ||
// Output-related | ||
returnPOT: false, | ||
writeFiles: true, | ||
destDir: "", | ||
logResults: false | ||
}; | ||
const resolvedOptions = Object.assign({}, defaultOptions, options); | ||
if (resolvedOptions.domainFromPOTPath === false && resolvedOptions.domainInPOPath === true && 0 >= resolvedOptions.domain.length) { | ||
throw new OptionsError( | ||
"Option domain should be a non-empty string when domainFromPOTPath is false and domainInPOPath is true." | ||
); | ||
} | ||
if (resolvedOptions.returnPOT && !resolvedOptions.writeFiles) { | ||
throw new OptionsError( | ||
"If option returnPOT is true, option writeFiles must be true or no PO files will be generated." | ||
); | ||
} | ||
return resolvedOptions; | ||
}; | ||
// src/shared.ts | ||
var import_node_path2 = require("path"); | ||
var import_safe_buffer = require("safe-buffer"); | ||
var import_matched = require("matched"); | ||
var import_node_fs2 = require("fs"); | ||
var import_gettext_parser = __toESM(require("gettext-parser")); | ||
var import_vinyl3 = __toESM(require("vinyl")); | ||
var import_ansi_colors2 = __toESM(require("ansi-colors")); | ||
var import_color_support2 = __toESM(require("color-support")); | ||
var import_node_fs3 = require("fs"); | ||
import_ansi_colors2.default.enabled = Boolean((0, import_color_support2.default)().hasBasic); | ||
var packageJSON2 = JSON.parse( | ||
(0, import_node_fs3.readFileSync)(new URL("../package.json", importMetaUrl), "utf-8") | ||
); | ||
var resolvePOTFilepaths = (options) => { | ||
if (isArray(options.potSources) && options.potSources.length && isString(options.potSources[0])) { | ||
options.potSources = (0, import_matched.sync)(options.potSources); | ||
} | ||
options._potFilenames = options.potSources.map( | ||
(f) => isString(f) ? f : f.path | ||
); | ||
if (0 >= options.potSources.length) { | ||
throw new plugin_error_default("No POT files found to process."); | ||
} | ||
if (1 < options.potSources.length && options.poSources) { | ||
throw new plugin_error_default( | ||
"When processing multiple POT files, leave option poSources empty.\nElse, the same generated PO files will be overwritten for each POT file.", | ||
"options" | ||
); | ||
} | ||
return options; | ||
}; | ||
var getPOFilepaths = (pot_filepath, options) => { | ||
const pot_name = (0, import_node_path2.basename)(pot_filepath, ".pot"); | ||
const domain = options.domainFromPOTPath ? pot_name : options.domain; | ||
const po_dir = options.srcDir ? options.srcDir : `${(0, import_node_path2.dirname)(pot_filepath)}/`; | ||
const po_files_glob = []; | ||
if (options.poSources) { | ||
po_files_glob.push(...options.poSources); | ||
} else { | ||
const locale_glob = "[a-z][a-z]?([a-z])?(_[A-Z][A-Z]?([A-Z]))?(_formal)"; | ||
const domain_glob = options.domainInPOPath ? `${domain}-` : ""; | ||
po_files_glob.push(`${po_dir}${domain_glob}${locale_glob}.po`); | ||
} | ||
const po_filepaths = (0, import_matched.sync)( | ||
po_files_glob, | ||
options.srcGlobOptions | ||
).sort(pathLineSort); | ||
return po_filepaths; | ||
}; | ||
var generatePO = (pot_object, po_object, po_filepath, options) => { | ||
let new_po_object = JSON.parse(JSON.stringify(pot_object)); | ||
new_po_object = fillPO(new_po_object, po_object, options); | ||
const new_po_output = compilePO(new_po_object, options); | ||
const new_po_filepath = (0, import_node_path2.basename)(po_filepath); | ||
if (options.writeFiles) { | ||
writePO(`${options.destDir}${new_po_filepath}`, new_po_output); | ||
} | ||
return new import_vinyl3.default({ | ||
contents: import_safe_buffer.Buffer.from(new_po_output), | ||
path: new_po_filepath | ||
}); | ||
}; | ||
var fillPO = (new_po_object, po_object, options) => { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m; | ||
for (const [ctxt, entries] of Object.entries(new_po_object.translations)) { | ||
for (const [msgid, entry] of Object.entries(entries)) { | ||
if (po_object.translations[ctxt] && po_object.translations[ctxt][msgid] && po_object.translations[ctxt][msgid]["msgstr"].length === entry["msgstr"].length) { | ||
new_po_object.translations[ctxt][msgid]["msgstr"] = [ | ||
...po_object.translations[ctxt][msgid]["msgstr"] | ||
]; | ||
} else if (options.defaultContextAsFallback && po_object.translations[""] && po_object.translations[""][msgid] && po_object.translations[""][msgid]["msgstr"].length === entry["msgstr"].length) { | ||
new_po_object.translations[ctxt][msgid]["msgstr"] = [ | ||
...po_object.translations[""][msgid]["msgstr"] | ||
]; | ||
new_po_object.translations[ctxt][msgid].comments = { | ||
...((_a = new_po_object.translations[ctxt][msgid]) == null ? void 0 : _a.comments) ?? {}, | ||
flag: [ | ||
"fuzzy", | ||
(_c = (_b = new_po_object.translations[ctxt][msgid]) == null ? void 0 : _b.comments) == null ? void 0 : _c.flag | ||
].filter((v) => v).join(", ") | ||
}; | ||
po_object.translations[""][msgid].comments = { | ||
...((_d = po_object.translations[""][msgid]) == null ? void 0 : _d.comments) ?? {}, | ||
translator: [ | ||
`NOTE: re-used for same message, but with context '${ctxt}'`, | ||
(_f = (_e = po_object.translations[""][msgid]) == null ? void 0 : _e.comments) == null ? void 0 : _f.translator | ||
].filter((v) => v).join("\n") | ||
}; | ||
} | ||
} | ||
} | ||
if (options.appendNonIncludedFromPO) { | ||
for (const [ctxt, entries] of Object.entries(po_object.translations)) { | ||
if (!new_po_object.translations[ctxt]) { | ||
new_po_object.translations[ctxt] = {}; | ||
} | ||
for (const [msgid, entry] of Object.entries(entries)) { | ||
if (!new_po_object.translations[ctxt][msgid]) { | ||
new_po_object.translations[ctxt][msgid] = entry; | ||
new_po_object.translations[ctxt][msgid].comments = { | ||
...((_g = new_po_object.translations[ctxt][msgid]) == null ? void 0 : _g.comments) ?? {}, | ||
...((_i = (_h = new_po_object.translations[ctxt][msgid]) == null ? void 0 : _h.comments) == null ? void 0 : _i.translator) && ((_j = entry == null ? void 0 : entry.comments) == null ? void 0 : _j.translator.match(/^DEPRECATED$/gm)) ? {} : { | ||
translator: isString( | ||
(_l = (_k = new_po_object.translations[ctxt][msgid]) == null ? void 0 : _k.comments) == null ? void 0 : _l.translator | ||
) ? "DEPRECATED\n" + (((_m = new_po_object.translations[ctxt][msgid].comments) == null ? void 0 : _m.translator) ?? "") : "DEPRECATED" | ||
} | ||
}; | ||
} | ||
} | ||
} | ||
} | ||
if (options.includePORevisionDate) { | ||
const d = /* @__PURE__ */ new Date(); | ||
const po_rev_date_string = [ | ||
`${d.getUTCFullYear()}`, | ||
`-${String(d.getUTCMonth() + 1).padStart(2, "0")}`, | ||
`-${String(d.getUTCDate()).padStart(2, "0")}`, | ||
` ${String(d.getUTCHours()).padStart(2, "0")}`, | ||
`:${String(d.getUTCMinutes()).padStart(2, "0")}`, | ||
"+0000" | ||
].join(""); | ||
new_po_object.headers["po-revision-date"] = po_rev_date_string; | ||
} | ||
if (options.includeGenerator) { | ||
new_po_object.headers["X-Generator"] = `${packageJSON2.name}/${packageJSON2.version}`; | ||
} | ||
return new_po_object; | ||
}; | ||
var compilePO = (new_po_object, options) => { | ||
return import_gettext_parser.default.po.compile(new_po_object, { | ||
foldLength: options.wrapLength, | ||
// Sort entries by first reference filepath and line number. | ||
sort: (a, b) => { | ||
var _a, _b, _c, _d, _e, _f; | ||
const b_deprecated = (_b = (_a = b.comments) == null ? void 0 : _a.translator) == null ? void 0 : _b.match(/^DEPRECATED$/gm); | ||
const a_deprecated = (_d = (_c = a.comments) == null ? void 0 : _c.translator) == null ? void 0 : _d.match(/^DEPRECATED$/gm); | ||
if (!a_deprecated && b_deprecated) | ||
return -1; | ||
if (a_deprecated && !b_deprecated) | ||
return 1; | ||
if (!((_e = b.comments) == null ? void 0 : _e.reference)) | ||
return -1; | ||
if (!((_f = a.comments) == null ? void 0 : _f.reference)) | ||
return 1; | ||
a = a.comments.reference.trim().split(/\s+/)[0]; | ||
b = b.comments.reference.trim().split(/\s+/)[0]; | ||
return pathLineSort(a, b); | ||
} | ||
}); | ||
}; | ||
var writePO = (new_po_filepath, new_po_output) => { | ||
const new_po_dir = (0, import_node_path2.dirname)(new_po_filepath); | ||
if (!(0, import_node_fs2.existsSync)(new_po_dir)) { | ||
(0, import_node_fs2.mkdirSync)(new_po_dir, { recursive: true }); | ||
} | ||
(0, import_node_fs2.writeFileSync)(new_po_filepath, new_po_output.toString()); | ||
}; | ||
var logResults = (pots, pos_in, pos_out, dest) => { | ||
pots.forEach((pot, i) => { | ||
var _a, _b; | ||
const pot_filepath = (0, import_node_path2.basename)(pot); | ||
const po_filepaths_in = (_a = pos_in[i]) == null ? void 0 : _a.map((po) => po); | ||
const po_filepaths_out = (_b = pos_out[i]) == null ? void 0 : _b.map((po) => po.path); | ||
const max_length_in = po_filepaths_in.reduce( | ||
(p, c4) => Math.max(c4.length, p), | ||
0 | ||
); | ||
console.log(""); | ||
if (po_filepaths_out && po_filepaths_out.length) { | ||
console.log(` ${import_ansi_colors2.default.bold.green("\u25A0")} ${import_ansi_colors2.default.white(pot_filepath)}`); | ||
po_filepaths_out.forEach((po_filepath_out, pi) => { | ||
console.log( | ||
[ | ||
" ", | ||
`${import_ansi_colors2.default.cyan(po_filepaths_in[pi].padEnd(max_length_in, " "))}`, | ||
` ${import_ansi_colors2.default.gray("\u2014\u25BA")} `, | ||
`${import_ansi_colors2.default.yellow(dest)}${import_ansi_colors2.default.yellow(po_filepath_out)}` | ||
].join("") | ||
); | ||
}); | ||
} else { | ||
console.log(` ${import_ansi_colors2.default.gray("\u25A0")} ${import_ansi_colors2.default.white(pot_filepath)}`); | ||
console.log(` ${import_ansi_colors2.default.gray("No PO files found.")}`); | ||
} | ||
}); | ||
console.log(""); | ||
}; | ||
// src/async.ts | ||
import_ansi_colors3.default.enabled = Boolean((0, import_color_support3.default)().hasBasic); | ||
var pot_input_files = []; | ||
var po_input_files = []; | ||
var parsePO = (po_filepath, resolve2, reject) => { | ||
fs.readFile(po_filepath, (err, file_content) => { | ||
if (err) | ||
reject(err); | ||
const po_object = import_gettext_parser2.default.po.parse(file_content); | ||
resolve2(po_object); | ||
}); | ||
}; | ||
var processPOT = (pot_file, options, resolve2, reject) => { | ||
const isVinyl3 = isVinyl(pot_file); | ||
const pot_filepath = isVinyl3 ? pot_file.path : pot_file; | ||
const po_filepaths = getPOFilepaths(pot_filepath, options); | ||
if (po_filepaths.length) { | ||
if (isVinyl3) { | ||
if (options.returnPOT) { | ||
pot_input_files.push(pot_file); | ||
} | ||
const pot_object = import_gettext_parser2.default.po.parse(pot_file.contents); | ||
resolve2([pot_object, po_filepaths]); | ||
} else { | ||
fs.readFile(pot_filepath, (err, pot_content) => { | ||
if (err) | ||
reject(err); | ||
if (options.returnPOT) { | ||
pot_input_files.push( | ||
new import_vinyl4.default({ | ||
contents: import_safe_buffer2.Buffer.from(pot_content), | ||
path: pot_filepath | ||
}) | ||
); | ||
} | ||
const pot_object = import_gettext_parser2.default.po.parse(pot_content); | ||
resolve2([pot_object, po_filepaths]); | ||
}); | ||
} | ||
} else { | ||
resolve2(null); | ||
} | ||
}; | ||
var async_default = (cb, options) => { | ||
if (typeof cb !== "function") { | ||
throw new plugin_error_default( | ||
"fillPotPo() requires a callback function as first parameter" | ||
); | ||
} | ||
let resolvedOptions; | ||
try { | ||
resolvedOptions = resolvePOTFilepaths(options_default(options)); | ||
} catch (error) { | ||
cb([false, error.toString()]); | ||
return; | ||
} | ||
pot_input_files = []; | ||
po_input_files = []; | ||
Promise.all( | ||
resolvedOptions.potSources.map((pot_file) => { | ||
const pot_filepath = isVinyl(pot_file) ? pot_file.relative : pot_file; | ||
return new Promise( | ||
(resolve2, reject) => { | ||
processPOT(pot_file, resolvedOptions, resolve2, reject); | ||
} | ||
).then(async (value) => { | ||
if (!value) { | ||
po_input_files.push([]); | ||
return []; | ||
} | ||
const pot_object = value[0]; | ||
const po_files = value[1]; | ||
po_input_files.push(po_files); | ||
const po_results = await Promise.all( | ||
po_files.map((po_file) => { | ||
return new Promise( | ||
(resolve2, reject) => { | ||
parsePO(po_file, resolve2, reject); | ||
} | ||
).then((po_object) => { | ||
return generatePO( | ||
pot_object, | ||
po_object, | ||
po_file, | ||
resolvedOptions | ||
); | ||
}).catch((error) => { | ||
throw new plugin_error_default( | ||
`${import_ansi_colors3.default.bold(error.message)} ${import_ansi_colors3.default.gray( | ||
`(PO ${import_ansi_colors3.default.white(po_file)})` | ||
)}` | ||
); | ||
}); | ||
}) | ||
); | ||
return po_results; | ||
}).catch((error) => { | ||
throw new plugin_error_default( | ||
`${error.message} ${import_ansi_colors3.default.gray(`(POT ${import_ansi_colors3.default.white(pot_filepath)})`)}` | ||
); | ||
}); | ||
}) | ||
).then((po_output_files2) => { | ||
if (resolvedOptions.logResults) { | ||
logResults( | ||
resolvedOptions._potFilenames, | ||
po_input_files, | ||
po_output_files2, | ||
resolvedOptions.destDir | ||
); | ||
} | ||
if (resolvedOptions.returnPOT) { | ||
cb([true, pot_input_files]); | ||
return; | ||
} | ||
cb([true, [].concat(...po_output_files2)]); | ||
}).catch((error) => { | ||
cb([false, error.toString()]); | ||
}); | ||
return; | ||
}; | ||
// src/sync.ts | ||
var fs2 = __toESM(require("fs")); | ||
var import_vinyl5 = __toESM(require("vinyl")); | ||
var import_gettext_parser3 = __toESM(require("gettext-parser")); | ||
var pot_input_files2 = []; | ||
var po_input_files2 = []; | ||
var po_output_files = []; | ||
var processPOs = (po_filepaths, pot_object, options) => { | ||
const pos = []; | ||
for (const po_filepath of po_filepaths) { | ||
const po_content = fs2.readFileSync(po_filepath).toString(); | ||
const po_object = import_gettext_parser3.default.po.parse(po_content); | ||
pos.push(generatePO(pot_object, po_object, po_filepath, options)); | ||
} | ||
po_output_files.push(pos); | ||
}; | ||
var processPOT2 = (pot_file, options) => { | ||
const isVinyl3 = isVinyl(pot_file); | ||
const pot_filepath = isVinyl3 ? pot_file.path : pot_file; | ||
const po_filepaths = getPOFilepaths(pot_filepath, options); | ||
po_input_files2.push(po_filepaths); | ||
if (po_filepaths.length) { | ||
let pot_content = ""; | ||
if (isVinyl3) { | ||
if (options.returnPOT) { | ||
pot_input_files2.push(pot_file); | ||
} | ||
pot_content = pot_file.contents; | ||
} else { | ||
const pot_content_buffer = fs2.readFileSync(pot_filepath); | ||
pot_content = pot_content_buffer.toString(); | ||
if (options.returnPOT) { | ||
pot_input_files2.push( | ||
new import_vinyl5.default({ | ||
contents: pot_content_buffer, | ||
path: pot_filepath | ||
}) | ||
); | ||
} | ||
} | ||
const pot_object = import_gettext_parser3.default.po.parse(pot_content); | ||
processPOs(po_filepaths, pot_object, options); | ||
} else { | ||
po_output_files.push([]); | ||
} | ||
}; | ||
var sync_default = (options) => { | ||
pot_input_files2 = []; | ||
po_input_files2 = []; | ||
po_output_files = []; | ||
const resolvedOptions = resolvePOTFilepaths(options_default(options)); | ||
resolvedOptions.potSources.forEach((pot_file) => { | ||
processPOT2(pot_file, resolvedOptions); | ||
}); | ||
if (resolvedOptions.logResults) { | ||
logResults( | ||
resolvedOptions._potFilenames, | ||
po_input_files2, | ||
po_output_files, | ||
resolvedOptions.destDir | ||
); | ||
} | ||
if (resolvedOptions.returnPOT) { | ||
return pot_input_files2; | ||
} | ||
return [].concat(...po_output_files); | ||
}; | ||
// src/index.ts | ||
var testOptions = { | ||
wrapLength: 77, | ||
defaultContextAsFallback: true, | ||
appendNonIncludedFromPO: true, | ||
includePORevisionDate: false, | ||
includeGenerator: false | ||
}; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
sync, | ||
testOptions | ||
}); | ||
var be=Object.create;var j=Object.defineProperty;var we=Object.getOwnPropertyDescriptor;var xe=Object.getOwnPropertyNames;var Re=Object.getPrototypeOf,$e=Object.prototype.hasOwnProperty;var ve=(e,t)=>{for(var r in t)j(e,r,{get:t[r],enumerable:!0})},ne=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of xe(t))!$e.call(e,o)&&o!==r&&j(e,o,{get:()=>t[o],enumerable:!(n=we(t,o))||n.enumerable});return e};var m=(e,t,r)=>(r=e!=null?be(Re(e)):{},ne(t||!e||!e.__esModule?j(r,"default",{value:e,enumerable:!0}):r,e)),ke=e=>ne(j({},"__esModule",{value:!0}),e);var Ne={};ve(Ne,{default:()=>Ue,prepareOptions:()=>$,sync:()=>re,testOptions:()=>ye});module.exports=ke(Ne);var Ce=()=>typeof document>"u"?new URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href,y=Ce();var Y=m(require("fs")),z=m(require("vinyl")),Pe=require("safe-buffer"),G=m(require("gettext-parser")),k=m(require("ansi-colors")),Se=m(require("color-support"));var se=m(require("util")),E=m(require("ansi-colors")),oe=m(require("color-support")),ae=require("fs");E.default.enabled=!!(0,oe.default)().hasBasic;var Fe=JSON.parse((0,ae.readFileSync)(new URL("../package.json",y),"utf-8")),q=class{message;category;constructor(t,r=""){this.message=t,this.category=r.slice(0,1).toUpperCase()+r.slice(1).toLowerCase()}toString(){return`${E.default.cyan(Fe.name)} ${E.default.bold.red(`${this.category}Error`)} ${this.message}`}[se.inspect.custom](){return this.toString()}},b=q;var R=require("path"),ue=m(require("vinyl"));var ie=m(require("vinyl"));var x=e=>Object.prototype.toString.call(e)==="[object Array]",le=e=>Object.prototype.toString.call(e)==="[object Object]",g=e=>Object.prototype.toString.call(e)==="[object String]",ce=e=>Object.prototype.toString.call(e)==="[object Boolean]",_=e=>x(e)?!!e.reduce((t,r)=>g(r)&&t,!0):!1,pe=e=>x(e)?!!e.reduce((t,r)=>ie.default.isVinyl(r)&&t,!0):!1,H=(e,t)=>{if(!g(e)||!g(t))throw new Error("pathLineSort: a or b not a string");let r,n;if([e,r]=e.split(":"),[t,n]=t.split(":"),e=e.replace(/(^\/|\/$)/g,""),t=t.replace(/(^\/|\/$)/g,""),e===t){if((!r||r==="")&&n&&n.length)return-1;if((!n||n==="")&&r&&r.length)return 1;if(r&&r.length&&n&&n.length)return parseInt(r)-parseInt(n)}let o=e.split("/"),s=t.split("/"),a=o.length,l=s.length,u=Math.max(a,l);for(let c=0;c<u;c++){if(c>=l||!s[c])return-1;if(c>=a||!o[c])return 1;let[f,d]=o[c].split(/\.(?=[^.]*$)/g),[O,h]=s[c].split(/\.(?=[^.]*$)/g),D=d&&d!=="",T=h&&h!=="";if(!D&&T)return-1;if(D&&!T||f.toUpperCase()>O.toUpperCase())return 1;if(f.toUpperCase()<O.toUpperCase())return-1;if(d&&h){if(d.toUpperCase()>h.toUpperCase())return 1;if(d.toUpperCase()<h.toUpperCase())return-1}}return 0};var P=class extends b{constructor(t){super(t,"options")}},W="./",De=e=>{if(le(e)){if("potSources"in e&&!g(e.potSources)&&!_(e.potSources)&&!ue.default.isVinyl(e.potSources)&&!pe(e.potSources))throw new P("Option potSources should be a string or Vinyl object, or an array of those.");if("poSources"in e&&e.poSources!==null&&!g(e.poSources)&&!_(e.poSources))throw new P("Option poSources should be a glob string or glob array.");if("wrapLength"in e&&(typeof e.wrapLength!="number"||0>=e.wrapLength))throw new P("If set, option wrapLength should be a number higher than 0.");let t=["srcDir","destDir","domain"];for(let n of t)if(n in e)if(g(e[n])){if(e[n].match(/\n/))throw new P(`Option ${n} can't contain newline characters.`)}else throw new P(`Option ${n} should be a string.`);let r=["writeFiles","returnPOT","domainFromPOTPath","domainInPOPath","defaultContextAsFallback","appendNonIncludedFromPO","includePORevisionDate","includeGenerator","logResults"];for(let n of r)if(n in e&&!ce(e[n]))throw new P(`Option ${n} should be a boolean.`)}else{if(g(e)||_(e))return{poSources:e};if(typeof e<"u")throw new P("Options should be an object of options, glob string or glob array.");return{}}return e},Te=e=>(typeof e.potSources<"u"&&(x(e.potSources)||(e.potSources=[e.potSources]),e.potSources=e.potSources.map(t=>g(t)?t.trim():t).filter(t=>!g(t)||t.length>0)),typeof e.poSources<"u"&&e.poSources!==null&&(x(e.poSources)||(e.poSources=[e.poSources]),e.poSources=e.poSources.map(t=>t.trim()).filter(t=>t.length>0)),e.srcDir&&(e.srcDir=(0,R.resolve)(e.srcDir.trim()),e.srcDir=`${(0,R.relative)(W,e.srcDir)}/`.replace(/\\/g,"/").replace(/\/+/g,"/").replace(/(?<!\.)\.\//g,"").replace(/^\//g,"")),e.destDir&&(e.destDir=(0,R.resolve)(e.destDir.trim()),e.destDir=`${(0,R.relative)(W,e.destDir)}/`.replace(/\\/g,"/").replace(/\/+/g,"/").replace(/(?<!\.)\.\//g,"").replace(/^\//g,"")),e.wrapLength&&(e.wrapLength=Math.ceil(e.wrapLength)),e),$=e=>{W=(0,R.resolve)(),e=De(e),e=Te(e);let r=Object.assign({},{potSources:["**/*.pot","!node_modules/**"],poSources:null,srcDir:"",domainInPOPath:!0,domainFromPOTPath:!0,domain:"",srcGlobOptions:{},wrapLength:77,defaultContextAsFallback:!1,appendNonIncludedFromPO:!1,includePORevisionDate:!1,includeGenerator:!0,returnPOT:!1,writeFiles:!0,destDir:"",logResults:!1},e);if(r.domainFromPOTPath===!1&&r.domainInPOPath===!0&&0>=r.domain.length)throw new P("Option domain should be a non-empty string when domainFromPOTPath is false and domainInPOPath is true.");if(r.returnPOT&&!r.writeFiles)throw new P("If option returnPOT is true, option writeFiles must be true or no PO files will be generated.");return r};var v=require("path"),me=require("safe-buffer"),X=require("matched"),F=require("fs"),de=m(require("gettext-parser")),ge=m(require("vinyl")),S=m(require("ansi-colors")),Oe=m(require("color-support"));var he=require("fs");S.default.enabled=!!(0,Oe.default)().hasBasic;var fe=JSON.parse((0,he.readFileSync)(new URL("../package.json",y),"utf-8")),L=e=>{if(x(e.potSources)&&e.potSources.length&&g(e.potSources[0])&&(e.potSources=(0,X.sync)(e.potSources)),e._potFilenames=e.potSources.map(t=>g(t)?t:t.path),0>=e.potSources.length)throw new b("No POT files found to process.");if(1<e.potSources.length&&e.poSources)throw new b(`When processing multiple POT files, leave option poSources empty. | ||
Else, the same generated PO files will be overwritten for each POT file.`,"options");return e},I=(e,t)=>{let r=(0,v.basename)(e,".pot"),n=t.domainFromPOTPath?r:t.domain,o=t.srcDir?t.srcDir:`${(0,v.dirname)(e)}/`,s=[];if(t.poSources)s.push(...t.poSources);else{let l="[a-z][a-z]?([a-z])?(_[A-Z][A-Z]?([A-Z]))?(_formal)",u=t.domainInPOPath?`${n}-`:"";s.push(`${o}${u}${l}.po`)}return(0,X.sync)(s,t.srcGlobOptions).sort(H)},U=(e,t,r,n)=>{let o=JSON.parse(JSON.stringify(e));o=Ve(o,t,n);let s=Ae(o,n),a=(0,v.basename)(r);return n.writeFiles&&je(`${n.destDir}${a}`,s),new ge.default({contents:me.Buffer.from(s),path:a})},Ve=(e,t,r)=>{var n,o,s,a,l,u,c,f,d,O,h,D,T;for(let[i,V]of Object.entries(e.translations))for(let[p,w]of Object.entries(V))t.translations[i]&&t.translations[i][p]&&t.translations[i][p].msgstr.length===w.msgstr.length?e.translations[i][p].msgstr=[...t.translations[i][p].msgstr]:r.defaultContextAsFallback&&t.translations[""]&&t.translations[""][p]&&t.translations[""][p].msgstr.length===w.msgstr.length&&(e.translations[i][p].msgstr=[...t.translations[""][p].msgstr],e.translations[i][p].comments={...((n=e.translations[i][p])==null?void 0:n.comments)??{},flag:["fuzzy",(s=(o=e.translations[i][p])==null?void 0:o.comments)==null?void 0:s.flag].filter(Z=>Z).join(", ")},t.translations[""][p].comments={...((a=t.translations[""][p])==null?void 0:a.comments)??{},translator:[`NOTE: re-used for same message, but with context '${i}'`,(u=(l=t.translations[""][p])==null?void 0:l.comments)==null?void 0:u.translator].filter(Z=>Z).join(` | ||
`)});if(r.appendNonIncludedFromPO)for(let[i,V]of Object.entries(t.translations)){e.translations[i]||(e.translations[i]={});for(let[p,w]of Object.entries(V))e.translations[i][p]||(e.translations[i][p]=w,e.translations[i][p].comments={...((c=e.translations[i][p])==null?void 0:c.comments)??{},...(d=(f=e.translations[i][p])==null?void 0:f.comments)!=null&&d.translator&&((O=w==null?void 0:w.comments)!=null&&O.translator.match(/^DEPRECATED$/gm))?{}:{translator:g((D=(h=e.translations[i][p])==null?void 0:h.comments)==null?void 0:D.translator)?`DEPRECATED | ||
`+(((T=e.translations[i][p].comments)==null?void 0:T.translator)??""):"DEPRECATED"}})}if(r.includePORevisionDate){let i=new Date,V=[`${i.getUTCFullYear()}`,`-${String(i.getUTCMonth()+1).padStart(2,"0")}`,`-${String(i.getUTCDate()).padStart(2,"0")}`,` ${String(i.getUTCHours()).padStart(2,"0")}`,`:${String(i.getUTCMinutes()).padStart(2,"0")}`,"+0000"].join("");e.headers["po-revision-date"]=V}return r.includeGenerator&&(e.headers["X-Generator"]=`${fe.name}/${fe.version}`),e},Ae=(e,t)=>de.default.po.compile(e,{foldLength:t.wrapLength,sort:(r,n)=>{var a,l,u,c,f,d;let o=(l=(a=n.comments)==null?void 0:a.translator)==null?void 0:l.match(/^DEPRECATED$/gm),s=(c=(u=r.comments)==null?void 0:u.translator)==null?void 0:c.match(/^DEPRECATED$/gm);return!s&&o?-1:s&&!o?1:(f=n.comments)!=null&&f.reference?(d=r.comments)!=null&&d.reference?(r=r.comments.reference.trim().split(/\s+/)[0],n=n.comments.reference.trim().split(/\s+/)[0],H(r,n)):1:-1}}),je=(e,t)=>{let r=(0,v.dirname)(e);(0,F.existsSync)(r)||(0,F.mkdirSync)(r,{recursive:!0}),(0,F.writeFileSync)(e,t.toString())},N=(e,t,r,n)=>{e.forEach((o,s)=>{var f,d;let a=(0,v.basename)(o),l=(f=t[s])==null?void 0:f.map(O=>O),u=(d=r[s])==null?void 0:d.map(O=>O.path),c=l.reduce((O,h)=>Math.max(h.length,O),0);console.log(""),u&&u.length?(console.log(` ${S.default.bold.green("\u25A0")} ${S.default.white(a)}`),u.forEach((O,h)=>{console.log([" ",`${S.default.cyan(l[h].padEnd(c," "))}`,` ${S.default.gray("\u2014\u25BA")} `,`${S.default.yellow(n)}${S.default.yellow(O)}`].join(""))})):(console.log(` ${S.default.gray("\u25A0")} ${S.default.white(a)}`),console.log(` ${S.default.gray("No PO files found.")}`))}),console.log("")};k.default.enabled=!!(0,Se.default)().hasBasic;var J=[],B=[],Ee=(e,t,r)=>{Y.readFile(e,(n,o)=>{n&&r(n);let s=G.default.po.parse(o);t(s)})},_e=(e,t,r,n)=>{let o=z.default.isVinyl(e),s=o?e.path:e,a=I(s,t);if(a.length)if(o){t.returnPOT&&J.push(e);let l=G.default.po.parse(e.contents);r([l,a])}else Y.readFile(s,(l,u)=>{l&&n(l),t.returnPOT&&J.push(new z.default({contents:Pe.Buffer.from(u),path:s}));let c=G.default.po.parse(u);r([c,a])});else r(null)},C=(e,t)=>{if(typeof e!="function")throw new b("fillPotPo() requires a callback function as first parameter");let r;try{r=L($(t))}catch(n){e([!1,n.toString()]);return}J=[],B=[],Promise.all(r.potSources.map(n=>{let o=z.default.isVinyl(n)?n.relative:n;return new Promise((s,a)=>{_e(n,r,s,a)}).then(async s=>{if(!s)return B.push([]),[];let a=s[0],l=s[1];return B.push(l),await Promise.all(l.map(c=>new Promise((f,d)=>{Ee(c,f,d)}).then(f=>U(a,f,c,r)).catch(f=>{throw new b(`${k.default.bold(f.message)} ${k.default.gray(`(PO ${k.default.white(c)})`)}`)})))}).catch(s=>{throw new b(`${s.message} ${k.default.gray(`(POT ${k.default.white(o)})`)}`)})})).then(n=>{if(r.logResults&&N(r._potFilenames,B,n,r.destDir),r.returnPOT){e([!0,J]);return}e([!0,[].concat(...n)])}).catch(n=>{e([!1,n.toString()])})};var ee=m(require("fs")),K=m(require("vinyl")),te=m(require("gettext-parser"));var M=[],Q=[],A=[],Le=(e,t,r)=>{let n=[];for(let o of e){let s=ee.readFileSync(o).toString(),a=te.default.po.parse(s);n.push(U(t,a,o,r))}A.push(n)},Ie=(e,t)=>{let r=K.default.isVinyl(e),n=r?e.path:e,o=I(n,t);if(Q.push(o),o.length){let s="";if(r)t.returnPOT&&M.push(e),s=e.contents;else{let l=ee.readFileSync(n);s=l.toString(),t.returnPOT&&M.push(new K.default({contents:l,path:n}))}let a=te.default.po.parse(s);Le(o,a,t)}else A.push([])},re=e=>{M=[],Q=[],A=[];let t=L($(e));return t.potSources.forEach(r=>{Ie(r,t)}),t.logResults&&N(t._potFilenames,Q,A,t.destDir),t.returnPOT?M:[].concat(...A)};var ye={wrapLength:77,defaultContextAsFallback:!0,appendNonIncludedFromPO:!0,includePORevisionDate:!1,includeGenerator:!1},Ue=C;typeof module<"u"&&(C.sync=re,C.testOptions=ye,C.prepareOptions=$,module.exports=C,module.exports.default=C);0&&(module.exports={prepareOptions,sync,testOptions}); |
{ | ||
"name": "fill-pot-po", | ||
"version": "2.1.17", | ||
"version": "2.2.0", | ||
"description": "Create pre-filled PO files from POT file, using previous PO files.", | ||
@@ -10,5 +10,5 @@ "main": "./dist/index.js", | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"require": "./dist/index.js", | ||
"import": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts" | ||
"import": "./dist/index.mjs" | ||
} | ||
@@ -18,3 +18,3 @@ }, | ||
"dev": "npm run build -- --watch src", | ||
"build": "tsup src/index.ts --format cjs,esm --dts --clean", | ||
"build": "tsup", | ||
"lint": "eslint src/*.ts test/*.ts", | ||
@@ -21,0 +21,0 @@ "lint:fix": "eslint --fix src/*.ts test/*.ts", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
43589
-35.55%140
-89.65%1
Infinity%11
83.33%