[Tools] Fix js multiline parsing in angular expressions (#24812) (#25053)

* [Tools] Fix js multiline parsing in angular expressions

* Add test
This commit is contained in:
Leanid Shutau 2018-11-05 10:46:52 +03:00 committed by GitHub
parent 03b6de2b10
commit 99a8488f8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 40 deletions

View file

@ -6,7 +6,7 @@ Array [
"kbn.dashboard.id-1",
Object {
"context": "Message context 1",
"message": "Message text 1",
"message": "Message text 1 {value}",
},
],
Array [

View file

@ -19,7 +19,7 @@
import cheerio from 'cheerio';
import { parse } from '@babel/parser';
import { isDirectiveLiteral, isObjectExpression } from '@babel/types';
import { isObjectExpression, isStringLiteral } from '@babel/types';
import {
isPropertyWithKey,
@ -42,8 +42,24 @@ import { createFailError } from '../../run';
*/
const ANGULAR_EXPRESSION_REGEX = /{{([^{}]|({([^']|('([^']|(\\'))*'))*?}))*}}+/g;
const LINEBREAK_REGEX = /\n/g;
const I18N_FILTER_MARKER = '| i18n: ';
function parseExpression(expression) {
let ast;
try {
ast = parse(`+${expression}`.replace(LINEBREAK_REGEX, ' '));
} catch (error) {
if (error instanceof SyntaxError) {
const errorWithContext = createParserErrorMessage(` ${expression}`, error);
throw createFailError(`Couldn't parse angular i18n expression:\n${errorWithContext}`);
}
}
return ast;
}
/**
* Extract default message from an angular filter expression argument
* @param {string} expression JavaScript code containing a filter object
@ -51,22 +67,7 @@ const I18N_FILTER_MARKER = '| i18n: ';
* @returns {{ message?: string, context?: string, valuesKeys: string[]] }}
*/
function parseFilterObjectExpression(expression, messageId) {
let ast;
try {
// parse an object expression instead of block statement
ast = parse(`+${expression}`);
} catch (error) {
if (error instanceof SyntaxError) {
const errorWithContext = createParserErrorMessage(` ${expression}`, error);
throw createFailError(
`Couldn't parse angular expression with i18n filter:\n${errorWithContext}`
);
}
throw error;
}
const ast = parseExpression(expression);
const objectExpressionNode = [...traverseNodes(ast.program.body)].find(node =>
isObjectExpression(node)
);
@ -97,30 +98,14 @@ function parseFilterObjectExpression(expression, messageId) {
}
function parseIdExpression(expression) {
let ast;
try {
ast = parse(expression);
} catch (error) {
if (error instanceof SyntaxError) {
const errorWithContext = createParserErrorMessage(expression, error);
throw createFailError(
`Couldn't parse angular expression with i18n filter:\n${errorWithContext}`
);
}
throw error;
}
const stringNode = [...traverseNodes(ast.program.directives)].find(node =>
isDirectiveLiteral(node)
);
const ast = parseExpression(expression);
const stringNode = [...traverseNodes(ast.program.body)].find(node => isStringLiteral(node));
if (!stringNode) {
throw createFailError(`Message id should be a string literal, but got: \n${expression}`);
}
return formatJSString(stringNode.value);
return stringNode ? formatJSString(stringNode.value) : null;
}
function trimCurlyBraces(string) {
@ -257,8 +242,10 @@ function* getDirectiveMessages(htmlContent) {
}
if (element.values) {
const nodes = parse(`+${element.values}`).program.body;
const valuesObjectNode = [...traverseNodes(nodes)].find(node => isObjectExpression(node));
const ast = parseExpression(element.values);
const valuesObjectNode = [...traverseNodes(ast.program.body)].find(node =>
isObjectExpression(node)
);
const valuesKeys = extractValuesKeysFromNode(valuesObjectNode);
checkValuesProperty(valuesKeys, message, messageId);

View file

@ -24,8 +24,12 @@ const htmlSourceBuffer = Buffer.from(`
<div>
<p
i18n-id="kbn.dashboard.id-1"
i18n-default-message="Message text 1"
i18n-default-message="Message text 1 {value}"
i18n-context="Message context 1"
i18n-values="{
value: 'Multiline
string',
}"
></p>
</div>
<div>