@lingui/babel-plugin-transform-js
Advanced tools
Comparing version 2.0.0-2 to 2.0.0-3
339
index.js
@@ -12,6 +12,2 @@ "use strict"; | ||
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); | ||
var _assign = _interopRequireDefault(require("@babel/runtime/core-js/object/assign")); | ||
var _getIterator2 = _interopRequireDefault(require("@babel/runtime/core-js/get-iterator")); | ||
@@ -23,2 +19,4 @@ | ||
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); | ||
var nlRe = /(?:\r\n|\r|\n)+\s+/g; | ||
@@ -32,2 +30,10 @@ var pluralRules = ["zero", "one", "two", "few", "many", "other"]; | ||
}; | ||
}; | ||
var initialProps = function initialProps() { | ||
return { | ||
text: "", | ||
values: {}, | ||
formats: {} | ||
}; | ||
}; // Plugin function | ||
@@ -45,2 +51,6 @@ | ||
name: "t" | ||
}) || t.isCallExpression(node.tag) && t.isMemberExpression(node.tag.callee) && t.isIdentifier(node.tag.callee.object, { | ||
name: "i18n" | ||
}) && t.isIdentifier(node.tag.callee.property, { | ||
name: "t" | ||
}); | ||
@@ -70,153 +80,207 @@ }; | ||
}; | ||
/** | ||
* Convert identifiers to *named* arguments and everything else | ||
* to *positional* arguments. | ||
* | ||
* Example: | ||
* `world` is named argument and `new Date()` is positional one | ||
* | ||
* Input: `Hello ${world}, today is ${new Date()}` | ||
* Output: `Hello {world}, today is {0}` | ||
*/ | ||
function processMethod(node, file, props) { | ||
function expressionToArgument(exp) { | ||
var name = t.isIdentifier(exp) ? exp.name : argumentGenerator(); | ||
var key = t.isIdentifier(exp) ? exp : t.numericLiteral(name); | ||
return { | ||
name: name, | ||
key: key | ||
}; | ||
} | ||
function processI18nMethod(node, file, props) { | ||
if (t.isCallExpression(node.tag)) { | ||
// Message with custom ID, where message is used as defaults | ||
// i18n.t('id')`Hello World` | ||
var defaults = node.tag.arguments[0]; | ||
if (!t.isStringLiteral(defaults)) { | ||
throw file.buildCodeFrameError(node.tag, "Message ID must be a string"); | ||
} | ||
var newProps = processTemplateLiteral(node.quasi, file, props); | ||
return (0, _extends2.default)({}, newProps, { | ||
text: defaults.value, | ||
defaults: props.text | ||
}); | ||
} // Message is used as the ID | ||
// i18n.t`Hello World` | ||
return processTemplateLiteral(node.quasi, file, props); | ||
} | ||
function processChoiceMethod(node, file, props) { | ||
var root = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; | ||
var choices = {}; | ||
var choicesType = node.callee.property.name.toLowerCase(); | ||
var defaults; | ||
var variable; | ||
var offset = ""; | ||
var choiceArguments = node.arguments[0]; | ||
// i18n.t | ||
if (isI18nMethod(node)) { | ||
processTemplateLiteral(node.quasi, file, props); // i18n.plural and i18n.select | ||
} else if (isChoiceMethod(node.callee)) { | ||
var exp = node; | ||
var choices = {}; | ||
var choicesType = node.callee.property.name.toLowerCase(); | ||
var variable; | ||
var offset = ""; | ||
var arg = exp.arguments[0]; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
if (t.isStringLiteral(choiceArguments)) { | ||
defaults = choiceArguments.value; | ||
choiceArguments = node.arguments[1]; | ||
} | ||
try { | ||
for (var _iterator = (0, _getIterator2.default)(arg.properties), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _attr = _step.value; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
if (_attr.computed) { | ||
throw file.buildCodeFrameError(_attr, "Computed properties aren't allowed."); | ||
} | ||
try { | ||
for (var _iterator = (0, _getIterator2.default)(choiceArguments.properties), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _attr = _step.value; | ||
var key = _attr.key; // key is either: | ||
// NumericLiteral => convert to `={number}` | ||
// StringLiteral => key.value | ||
// Literal => key.name | ||
if (_attr.computed) { | ||
throw file.buildCodeFrameError(_attr, "Computed properties aren't allowed."); | ||
} | ||
var name = t.isNumericLiteral(key) ? "=".concat(key.value) : key.name || key.value; | ||
var key = _attr.key; // key is either: | ||
// NumericLiteral => convert to `={number}` | ||
// StringLiteral => key.value | ||
// Literal => key.name | ||
if (name === "value") { | ||
var _exp = _attr.value; | ||
variable = t.isIdentifier(_exp) ? _exp.name : argumentGenerator(); | ||
var name = t.isNumericLiteral(key) ? "=".concat(key.value) : key.name || key.value; | ||
var _key = t.isIdentifier(_exp) ? _exp : t.numericLiteral(variable); | ||
if (name === "value") { | ||
var exp = _attr.value; | ||
props.values[variable] = t.objectProperty(_key, _exp); | ||
} else if (choicesType !== "select" && name === "offset") { | ||
// offset is static parameter, so it must be either string or number | ||
if (!t.isNumericLiteral(_attr.value) && !t.isStringLiteral(_attr.value)) { | ||
throw file.buildCodeFrameError(node.callee, "Offset argument cannot be a variable."); | ||
} | ||
var _expressionToArgument = expressionToArgument(exp), | ||
_name = _expressionToArgument.name, | ||
_key = _expressionToArgument.key; | ||
offset = " offset:".concat(_attr.value.value); | ||
} else { | ||
var value = ""; | ||
variable = _name; | ||
props.values[_name] = t.objectProperty(_key, exp); | ||
} else if (choicesType !== "select" && name === "offset") { | ||
// offset is static parameter, so it must be either string or number | ||
if (!t.isNumericLiteral(_attr.value) && !t.isStringLiteral(_attr.value)) { | ||
throw file.buildCodeFrameError(node.callee, "Offset argument cannot be a variable."); | ||
} | ||
if (t.isTemplateLiteral(_attr.value)) { | ||
props = processTemplateLiteral(_attr.value, file, (0, _assign.default)({}, props, { | ||
text: "" | ||
})); | ||
value = props.text; | ||
} else if (t.isCallExpression(_attr.value)) { | ||
props = processMethod(_attr.value, file, (0, _assign.default)({}, props, { | ||
text: "" | ||
})); | ||
value = props.text; | ||
} else { | ||
value = _attr.value.value; | ||
} | ||
offset = " offset:".concat(_attr.value.value); | ||
} else { | ||
var value = ""; | ||
choices[name] = value; | ||
if (t.isTemplateLiteral(_attr.value)) { | ||
props = processTemplateLiteral(_attr.value, file, (0, _extends2.default)({}, props, { | ||
text: "" | ||
})); | ||
value = props.text; | ||
} else if (t.isCallExpression(_attr.value)) { | ||
props = processMethod(_attr.value, file, (0, _extends2.default)({}, props, { | ||
text: "" | ||
})); | ||
value = props.text; | ||
} else { | ||
value = _attr.value.value; | ||
} | ||
} // missing value | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
choices[name] = value; | ||
} | ||
} // missing value | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
if (variable === undefined) { | ||
throw file.buildCodeFrameError(node.callee, "Value argument is missing."); | ||
} | ||
if (variable === undefined) { | ||
throw file.buildCodeFrameError(node.callee, "Value argument is missing."); | ||
} | ||
var choicesKeys = (0, _keys.default)(choices); // 'other' choice is required | ||
var choicesKeys = (0, _keys.default)(choices); // 'other' choice is required | ||
if (!choicesKeys.length) { | ||
throw file.buildCodeFrameError(node.callee, "Missing ".concat(choicesType, " choices. At least fallback argument 'other' is required.")); | ||
} else if (!(0, _includes.default)(choicesKeys, "other")) { | ||
throw file.buildCodeFrameError(node.callee, "Missing fallback argument 'other'."); | ||
} // validate plural rules | ||
if (!choicesKeys.length) { | ||
throw file.buildCodeFrameError(node.callee, "Missing ".concat(choicesType, " choices. At least fallback argument 'other' is required.")); | ||
} else if (!(0, _includes.default)(choicesKeys, "other")) { | ||
throw file.buildCodeFrameError(node.callee, "Missing fallback argument 'other'."); | ||
} // validate plural rules | ||
if (choicesType === "plural" || choicesType === "selectordinal") { | ||
choicesKeys.forEach(function (rule) { | ||
if (!(0, _includes.default)(pluralRules, rule) && !/=\d+/.test(rule)) { | ||
throw file.buildCodeFrameError(node.callee, "Invalid plural rule '".concat(rule, "'. Must be ").concat(pluralRules.join(", "), " or exact number depending on your source language ('one' and 'other' for English).")); | ||
} | ||
}); | ||
} | ||
if (choicesType === "plural" || choicesType === "selectordinal") { | ||
choicesKeys.forEach(function (rule) { | ||
if (!(0, _includes.default)(pluralRules, rule) && !/=\d+/.test(rule)) { | ||
throw file.buildCodeFrameError(node.callee, "Invalid plural rule '".concat(rule, "'. Must be ").concat(pluralRules.join(", "), " or exact number depending on your source language ('one' and 'other' for English).")); | ||
} | ||
}); | ||
} | ||
var argument = choicesKeys.map(function (form) { | ||
return "".concat(form, " {").concat(choices[form], "}"); | ||
}).join(" "); | ||
var format = "".concat(variable, ", ").concat(choicesType, ",").concat(offset, " ").concat(argument); | ||
props.text = root ? "{".concat(format, "}") : format; | ||
} else if (isFormatMethod(node.callee)) { | ||
var _exp2 = node.arguments[0]; // missing value | ||
var argument = choicesKeys.map(function (form) { | ||
return "".concat(form, " {").concat(choices[form], "}"); | ||
}).join(" "); | ||
var format = "".concat(variable, ", ").concat(choicesType, ",").concat(offset, " ").concat(argument); | ||
props.text = root ? "{".concat(format, "}") : format; | ||
if (_exp2 === undefined) { | ||
throw file.buildCodeFrameError(node.callee, "The first argument of format function must be a variable."); | ||
} | ||
if (defaults) { | ||
return (0, _extends2.default)({}, props, { | ||
text: defaults, | ||
defaults: props.text | ||
}); | ||
} | ||
var _variable = t.isIdentifier(_exp2) ? _exp2.name : argumentGenerator(); | ||
return props; | ||
} | ||
var _key2 = t.isIdentifier(_exp2) ? _exp2 : t.numericLiteral(_variable); | ||
function processFormatMethod(node, file, props, root) { | ||
var exp = node.arguments[0]; // missing value | ||
var type = node.callee.property.name; | ||
var parts = [_variable, // variable name | ||
type // format type | ||
]; | ||
var _format = ""; | ||
var formatArg = node.arguments[1]; | ||
if (exp === undefined) { | ||
throw file.buildCodeFrameError(node.callee, "The first argument of format function must be a variable."); | ||
} | ||
if (!formatArg) {// Do not throw validation error when format doesn't exist | ||
} else if (t.isStringLiteral(formatArg)) { | ||
_format = formatArg.value; | ||
} else if (t.isIdentifier(formatArg) || t.isObjectExpression(formatArg)) { | ||
if (t.isIdentifier(formatArg)) { | ||
_format = formatArg.name; | ||
} else { | ||
var formatName = new RegExp("^".concat(type, "\\d+$")); | ||
var existing = (0, _keys.default)(props.formats).filter(function (name) { | ||
return formatName.test(name); | ||
}); | ||
_format = "".concat(type).concat(existing.length || 0); | ||
} | ||
var _expressionToArgument2 = expressionToArgument(exp), | ||
name = _expressionToArgument2.name, | ||
key = _expressionToArgument2.key; | ||
props.formats[_format] = t.objectProperty(t.identifier(_format), formatArg); | ||
var type = node.callee.property.name; | ||
var parts = [name, // variable name | ||
type // format type | ||
]; | ||
var format = ""; | ||
var formatArg = node.arguments[1]; | ||
if (!formatArg) {// Do not throw validation error when format doesn't exist | ||
} else if (t.isStringLiteral(formatArg)) { | ||
format = formatArg.value; | ||
} else if (t.isIdentifier(formatArg) || t.isObjectExpression(formatArg)) { | ||
if (t.isIdentifier(formatArg)) { | ||
format = formatArg.name; | ||
} else { | ||
throw file.buildCodeFrameError(formatArg, "Format can be either string for buil-in formats, variable or object for custom defined formats."); | ||
var formatName = new RegExp("^".concat(type, "\\d+$")); | ||
var existing = (0, _keys.default)(props.formats).filter(function (name) { | ||
return formatName.test(name); | ||
}); | ||
format = "".concat(type).concat(existing.length || 0); | ||
} | ||
if (_format) parts.push(_format); | ||
props.values[_variable] = t.objectProperty(_key2, _exp2); | ||
props.text += "".concat(parts.join(",")); | ||
props.formats[format] = t.objectProperty(t.identifier(format), formatArg); | ||
} else { | ||
throw file.buildCodeFrameError(formatArg, "Format can be either string for buil-in formats, variable or object for custom defined formats."); | ||
} | ||
if (format) parts.push(format); | ||
props.values[name] = t.objectProperty(key, exp); | ||
props.text += "".concat(parts.join(",")); | ||
return props; | ||
@@ -242,4 +306,6 @@ } | ||
} else { | ||
var name = t.isIdentifier(item) ? item.name : argumentGenerator(); | ||
var key = t.isIdentifier(item) ? item : t.numericLiteral(name); | ||
var _expressionToArgument3 = expressionToArgument(item), | ||
name = _expressionToArgument3.name, | ||
key = _expressionToArgument3.key; | ||
props.text += "{".concat(name, "}"); | ||
@@ -252,2 +318,19 @@ props.values[name] = t.objectProperty(key, item); | ||
function processMethod(node, file, props) { | ||
var root = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; | ||
if (isI18nMethod(node)) { | ||
// i18n.t | ||
return processI18nMethod(node, file, props); | ||
} else if (isChoiceMethod(node.callee)) { | ||
// i18n.plural, i18n.select and i18n.selectOrdinal | ||
return processChoiceMethod(node, file, props, root); | ||
} else if (isFormatMethod(node.callee)) { | ||
// i18n.date, i18n.number | ||
return processFormatMethod(node, file, props, root); | ||
} | ||
return props; | ||
} | ||
function CallExpression(path, _ref2) { | ||
@@ -257,9 +340,3 @@ var file = _ref2.file; | ||
var props = processMethod(path.node, file, { | ||
text: "", | ||
values: {}, | ||
formats: {} | ||
}, | ||
/* root= */ | ||
true); | ||
var props = processMethod(path.node, file, initialProps(), true); | ||
var text = props.text.replace(nlRe, " ").trim(); | ||
@@ -273,2 +350,6 @@ if (!text) return; // 2. Replace complex expression with single call to i18n._ | ||
tOptions.push(t.objectProperty(t.identifier("formats"), t.objectExpression(formatsList))); | ||
} | ||
if (props.defaults) { | ||
tOptions.push(t.objectProperty(t.identifier("defaults"), t.stringLiteral(props.defaults))); | ||
} // arguments of i18n._(messageId: string, values: Object, options: Object) | ||
@@ -275,0 +356,0 @@ |
{ | ||
"name": "@lingui/babel-plugin-transform-js", | ||
"version": "2.0.0-2", | ||
"version": "2.0.0-3", | ||
"description": "Transform lingui-i18n methods to ICU message format", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15506
301