fix(localize): support downleveled inlined helper localize calls (#40754)
When the downleveling helper function has been inlined into the `$localize` call, it is a bit more tricky to parse out the cooked and raw strings. There was already code to do this but it assumed that the `cooked` and `raw` items were both arrays. Sometimes the `raw` array is just a copy of the `cooked` array via an expression similar to `raw || (raw=tcookedslice(0))`. This commit changes the `unwrapMessagePartsFromLocalizeCall()` function to be able to handle such a situation. Fixes #40702 PR Close #40754
This commit is contained in:
parent
4e4fcacb6d
commit
ce44a3d1dc
|
@ -89,7 +89,7 @@ export function unwrapMessagePartsFromLocalizeCall(
|
|||
// If there is no call to `__makeTemplateObject(...)`, then `raw` must be the same as `cooked`.
|
||||
let raw = cooked;
|
||||
|
||||
// Check for cached call of the form `x || x = __makeTemplateObject(...)`
|
||||
// Check for a memoized form: `x || x = ...`
|
||||
if (cooked.isLogicalExpression() && cooked.node.operator === '||' &&
|
||||
cooked.get('left').isIdentifier()) {
|
||||
const right = cooked.get('right');
|
||||
|
@ -105,15 +105,22 @@ export function unwrapMessagePartsFromLocalizeCall(
|
|||
// This is a minified sequence expression, where the first two expressions in the sequence
|
||||
// are assignments of the cooked and raw arrays respectively.
|
||||
const [first, second] = expressions;
|
||||
if (first.isAssignmentExpression() && second.isAssignmentExpression()) {
|
||||
if (first.isAssignmentExpression()) {
|
||||
cooked = first.get('right');
|
||||
if (!cooked.isExpression()) {
|
||||
throw new BabelParseError(
|
||||
first.node, 'Unexpected cooked value, expected an expression.');
|
||||
}
|
||||
raw = second.get('right');
|
||||
if (!raw.isExpression()) {
|
||||
throw new BabelParseError(second.node, 'Unexpected raw value, expected an expression.');
|
||||
if (second.isAssignmentExpression()) {
|
||||
raw = second.get('right');
|
||||
if (!raw.isExpression()) {
|
||||
throw new BabelParseError(
|
||||
second.node, 'Unexpected raw value, expected an expression.');
|
||||
}
|
||||
} else {
|
||||
// If the second expression is not an assignment then it is probably code to take a copy
|
||||
// of the cooked array. For example: `raw || (raw=cooked.slice(0))`.
|
||||
raw = cooked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,6 +132,104 @@ runInEachFileSystem(() => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('should return an array of string literals and locations from a (Babel helper) downleveled tagged template',
|
||||
() => {
|
||||
let localizeCall = getLocalizeCall(
|
||||
`$localize(babelHelpers.taggedTemplateLiteral(['a', 'b\\t', 'c'], ['a', 'b\\\\t', 'c']), 1, 2)`);
|
||||
const [parts, locations] = unwrapMessagePartsFromLocalizeCall(localizeCall, fs);
|
||||
expect(parts).toEqual(['a', 'b\t', 'c']);
|
||||
expect(parts.raw).toEqual(['a', 'b\\t', 'c']);
|
||||
expect(locations).toEqual([
|
||||
{
|
||||
start: {line: 0, column: 65},
|
||||
end: {line: 0, column: 68},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `'a'`,
|
||||
},
|
||||
{
|
||||
start: {line: 0, column: 70},
|
||||
end: {line: 0, column: 76},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `'b\\\\t'`,
|
||||
},
|
||||
{
|
||||
start: {line: 0, column: 78},
|
||||
end: {line: 0, column: 81},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `'c'`,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return an array of string literals and locations from a memoized downleveled tagged template',
|
||||
() => {
|
||||
let localizeCall = getLocalizeCall(`
|
||||
var _templateObject;
|
||||
$localize(_templateObject || (_templateObject = __makeTemplateObject(['a', 'b\\t', 'c'], ['a', 'b\\\\t', 'c'])), 1, 2)`);
|
||||
const [parts, locations] = unwrapMessagePartsFromLocalizeCall(localizeCall, fs);
|
||||
expect(parts).toEqual(['a', 'b\t', 'c']);
|
||||
expect(parts.raw).toEqual(['a', 'b\\t', 'c']);
|
||||
expect(locations).toEqual([
|
||||
{
|
||||
start: {line: 2, column: 105},
|
||||
end: {line: 2, column: 108},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `'a'`,
|
||||
},
|
||||
{
|
||||
start: {line: 2, column: 110},
|
||||
end: {line: 2, column: 116},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `'b\\\\t'`,
|
||||
},
|
||||
{
|
||||
start: {line: 2, column: 118},
|
||||
end: {line: 2, column: 121},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `'c'`,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return an array of string literals and locations from a memoized (inlined Babel helper) downleveled tagged template',
|
||||
() => {
|
||||
let localizeCall = getLocalizeCall(`
|
||||
var e,t,n;
|
||||
$localize(e ||
|
||||
(
|
||||
t=["a","b\t","c"],
|
||||
n || (n=t.slice(0)),
|
||||
e = Object.freeze(
|
||||
Object.defineProperties(t, { raw: { value: Object.freeze(n) } })
|
||||
)
|
||||
),
|
||||
1,2
|
||||
)`);
|
||||
const [parts, locations] = unwrapMessagePartsFromLocalizeCall(localizeCall, fs);
|
||||
expect(parts).toEqual(['a', 'b\t', 'c']);
|
||||
expect(parts.raw).toEqual(['a', 'b\t', 'c']);
|
||||
expect(locations).toEqual([
|
||||
{
|
||||
start: {line: 4, column: 21},
|
||||
end: {line: 4, column: 24},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `"a"`,
|
||||
},
|
||||
{
|
||||
start: {line: 4, column: 25},
|
||||
end: {line: 4, column: 29},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `"b\t"`,
|
||||
},
|
||||
{
|
||||
start: {line: 4, column: 30},
|
||||
end: {line: 4, column: 33},
|
||||
file: absoluteFrom('/test/file.js'),
|
||||
text: `"c"`,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return an array of string literals and locations from a lazy load template helper',
|
||||
() => {
|
||||
let localizeCall = getLocalizeCall(`
|
||||
|
|
Loading…
Reference in New Issue