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`.
|
// If there is no call to `__makeTemplateObject(...)`, then `raw` must be the same as `cooked`.
|
||||||
let raw = 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 === '||' &&
|
if (cooked.isLogicalExpression() && cooked.node.operator === '||' &&
|
||||||
cooked.get('left').isIdentifier()) {
|
cooked.get('left').isIdentifier()) {
|
||||||
const right = cooked.get('right');
|
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
|
// This is a minified sequence expression, where the first two expressions in the sequence
|
||||||
// are assignments of the cooked and raw arrays respectively.
|
// are assignments of the cooked and raw arrays respectively.
|
||||||
const [first, second] = expressions;
|
const [first, second] = expressions;
|
||||||
if (first.isAssignmentExpression() && second.isAssignmentExpression()) {
|
if (first.isAssignmentExpression()) {
|
||||||
cooked = first.get('right');
|
cooked = first.get('right');
|
||||||
if (!cooked.isExpression()) {
|
if (!cooked.isExpression()) {
|
||||||
throw new BabelParseError(
|
throw new BabelParseError(
|
||||||
first.node, 'Unexpected cooked value, expected an expression.');
|
first.node, 'Unexpected cooked value, expected an expression.');
|
||||||
}
|
}
|
||||||
raw = second.get('right');
|
if (second.isAssignmentExpression()) {
|
||||||
if (!raw.isExpression()) {
|
raw = second.get('right');
|
||||||
throw new BabelParseError(second.node, 'Unexpected raw value, expected an expression.');
|
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',
|
it('should return an array of string literals and locations from a lazy load template helper',
|
||||||
() => {
|
() => {
|
||||||
let localizeCall = getLocalizeCall(`
|
let localizeCall = getLocalizeCall(`
|
||||||
|
|
Loading…
Reference in New Issue