Skip to content

Commit

Permalink
Replace default Error with FailError
Browse files Browse the repository at this point in the history
  • Loading branch information
LeanidShutau committed Aug 28, 2018
1 parent b90f21a commit 08f91bc
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 74 deletions.
4 changes: 2 additions & 2 deletions src/dev/i18n/__snapshots__/extract_code_messages.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ Array [
]
`;

exports[`extractCodeMessages throws on empty id 1`] = `"Empty \\"id\\" value in i18n() or i18n.translate() is not allowed."`;
exports[`extractCodeMessages throws on empty id 1`] = `"[37m[41m I18N ERROR [49m[39m Empty \\"id\\" value in i18n() or i18n.translate() is not allowed."`;

exports[`extractCodeMessages throws on missing defaultMessage 1`] = `"Empty defaultMessage in intl.formatMessage() is not allowed (\\"message-id\\")."`;
exports[`extractCodeMessages throws on missing defaultMessage 1`] = `"[37m[41m I18N ERROR [49m[39m Empty defaultMessage in intl.formatMessage() is not allowed (\\"message-id\\")."`;
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,10 @@ exports[`dev/i18n/extract_default_translations injects default formats into en.j
}"
`;

exports[`dev/i18n/extract_default_translations throws on wrong message namespace 1`] = `"Expected \\"wrong_plugin_namespace.message-id\\" id to have \\"plugin_2\\" namespace. See i18nrc.json for the list of supported namespaces."`;
exports[`dev/i18n/extract_default_translations throws on id collision 1`] = `
" I18N ERROR  Error in src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_3/test_file.jsx
Error:  I18N ERROR  There is more than one default message for the same id \\"plugin_3.duplicate_id\\":
\\"Message 1\\" and \\"Message 2\\""
`;

exports[`dev/i18n/extract_default_translations throws on wrong message namespace 1`] = `" I18N ERROR  Expected \\"wrong_plugin_namespace.message-id\\" id to have \\"plugin_2\\" namespace. See i18nrc.json for the list of supported namespaces."`;
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Array [
]
`;

exports[`dev/i18n/extract_handlebars_messages throws on empty id 1`] = `"Empty id argument in Handlebars i18n is not allowed."`;
exports[`dev/i18n/extract_handlebars_messages throws on empty id 1`] = `"[37m[41m I18N ERROR [49m[39m Empty id argument in Handlebars i18n is not allowed."`;

exports[`dev/i18n/extract_handlebars_messages throws on missing defaultMessage property 1`] = `"Empty defaultMessage in Handlebars i18n is not allowed (\\"message-id\\")."`;
exports[`dev/i18n/extract_handlebars_messages throws on missing defaultMessage property 1`] = `"[37m[41m I18N ERROR [49m[39m Empty defaultMessage in Handlebars i18n is not allowed (\\"message-id\\")."`;

exports[`dev/i18n/extract_handlebars_messages throws on wrong number of arguments 1`] = `"Wrong number of arguments for handlebars i18n call."`;
exports[`dev/i18n/extract_handlebars_messages throws on wrong number of arguments 1`] = `"[37m[41m I18N ERROR [49m[39m Wrong number of arguments for handlebars i18n call."`;

exports[`dev/i18n/extract_handlebars_messages throws on wrong properties argument type 1`] = `"Properties string in Handlebars i18n should be a string literal (\\"ui.id-1\\")."`;
exports[`dev/i18n/extract_handlebars_messages throws on wrong properties argument type 1`] = `"[37m[41m I18N ERROR [49m[39m Properties string in Handlebars i18n should be a string literal (\\"ui.id-1\\")."`;
4 changes: 2 additions & 2 deletions src/dev/i18n/__snapshots__/extract_html_messages.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ Array [
]
`;

exports[`dev/i18n/extract_html_messages throws on empty i18n-id 1`] = `"Empty \\"i18n-id\\" value in angular directive is not allowed."`;
exports[`dev/i18n/extract_html_messages throws on empty i18n-id 1`] = `"[37m[41m I18N ERROR [49m[39m Empty \\"i18n-id\\" value in angular directive is not allowed."`;

exports[`dev/i18n/extract_html_messages throws on missing i18n-default-message attribute 1`] = `"Empty defaultMessage in angular directive is not allowed (\\"message-id\\")."`;
exports[`dev/i18n/extract_html_messages throws on missing i18n-default-message attribute 1`] = `"[37m[41m I18N ERROR [49m[39m Empty defaultMessage in angular directive is not allowed (\\"message-id\\")."`;
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ Array [
]
`;

exports[`extractI18nCallMessages throws if defaultMessage is not a string literal 1`] = `"defaultMessage value in i18n() or i18n.translate() should be a string literal (\\"message-id\\")."`;
exports[`extractI18nCallMessages throws if defaultMessage is not a string literal 1`] = `"[37m[41m I18N ERROR [49m[39m defaultMessage value in i18n() or i18n.translate() should be a string literal (\\"message-id\\")."`;

exports[`extractI18nCallMessages throws if message id value is not a string literal 1`] = `"Message id in i18n() or i18n.translate() should be a string literal."`;
exports[`extractI18nCallMessages throws if message id value is not a string literal 1`] = `"[37m[41m I18N ERROR [49m[39m Message id in i18n() or i18n.translate() should be a string literal."`;

exports[`extractI18nCallMessages throws if properties object is not provided 1`] = `"Empty defaultMessage in i18n() or i18n.translate() is not allowed (\\"message-id\\")."`;
exports[`extractI18nCallMessages throws if properties object is not provided 1`] = `"[37m[41m I18N ERROR [49m[39m Empty defaultMessage in i18n() or i18n.translate() is not allowed (\\"message-id\\")."`;

exports[`extractI18nCallMessages throws on empty defaultMessage 1`] = `"Empty defaultMessage in i18n() or i18n.translate() is not allowed (\\"message-id\\")."`;
exports[`extractI18nCallMessages throws on empty defaultMessage 1`] = `"[37m[41m I18N ERROR [49m[39m Empty defaultMessage in i18n() or i18n.translate() is not allowed (\\"message-id\\")."`;
4 changes: 2 additions & 2 deletions src/dev/i18n/__snapshots__/extract_pug_messages.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ Array [
]
`;

exports[`extractPugMessages throws on empty id 1`] = `"Empty \\"id\\" value in i18n() or i18n.translate() is not allowed."`;
exports[`extractPugMessages throws on empty id 1`] = `"[37m[41m I18N ERROR [49m[39m Empty \\"id\\" value in i18n() or i18n.translate() is not allowed."`;

exports[`extractPugMessages throws on missing default message 1`] = `"Empty defaultMessage in i18n() or i18n.translate() is not allowed (\\"message-id\\")."`;
exports[`extractPugMessages throws on missing default message 1`] = `"[37m[41m I18N ERROR [49m[39m Empty defaultMessage in i18n() or i18n.translate() is not allowed (\\"message-id\\")."`;
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Array [
]
`;
exports[`dev/i18n/extract_react_messages extractIntlMessages throws if context value is not a string literal 1`] = `"context value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extract_react_messages extractIntlMessages throws if context value is not a string literal 1`] = `"[37m[41m I18N ERROR [49m[39m context value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extract_react_messages extractIntlMessages throws if defaultMessage value is not a string literal 1`] = `"defaultMessage value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extract_react_messages extractIntlMessages throws if defaultMessage value is not a string literal 1`] = `"[37m[41m I18N ERROR [49m[39m defaultMessage value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extract_react_messages extractIntlMessages throws if message id is not a string literal 1`] = `"Message id should be a string literal."`;
exports[`dev/i18n/extract_react_messages extractIntlMessages throws if message id is not a string literal 1`] = `"[37m[41m I18N ERROR [49m[39m Message id should be a string literal."`;
16 changes: 10 additions & 6 deletions src/dev/i18n/extract_default_translations.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,24 @@ import path from 'path';
import { i18n } from '@kbn/i18n';
import JSON5 from 'json5';
import normalize from 'normalize-path';
import chalk from 'chalk';

import { extractHtmlMessages } from './extract_html_messages';
import { extractCodeMessages } from './extract_code_messages';
import { extractPugMessages } from './extract_pug_messages';
import { extractHandlebarsMessages } from './extract_handlebars_messages';
import { globAsync, readFileAsync, writeFileAsync } from './utils';
import { paths, exclude } from '../../../.i18nrc.json';
import { createFailError } from '../run';

const ESCAPE_SINGLE_QUOTE_REGEX = /\\([\s\S])|(')/g;

function addMessageToMap(targetMap, key, value) {
const existingValue = targetMap.get(key);
if (targetMap.has(key) && existingValue.message !== value.message) {
throw new Error(
`There is more than one default message for the same id "${key}": \
"${existingValue.message}" and "${value.message}"`
);
throw createFailError(`${chalk.white.bgRed(' I18N ERROR ')} \
There is more than one default message for the same id "${key}":
"${existingValue.message}" and "${value.message}"`);
}
targetMap.set(key, value);
}
Expand Down Expand Up @@ -78,7 +79,8 @@ export function validateMessageNamespace(id, filePath) {
);

if (!id.startsWith(`${expectedNamespace}.`)) {
throw new Error(`Expected "${id}" id to have "${expectedNamespace}" namespace. \
throw createFailError(`${chalk.white.bgRed(' I18N ERROR ')} \
Expected "${id}" id to have "${expectedNamespace}" namespace. \
See i18nrc.json for the list of supported namespaces.`);
}
}
Expand Down Expand Up @@ -131,7 +133,9 @@ export async function extractMessagesFromPathToMap(inputPath, targetMap) {
addMessageToMap(targetMap, id, value);
}
} catch (error) {
throw new Error(`Error in ${name}\n${error.message || error}`);
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} Error in ${normalizePath(name)}\n${error}`
);
}
}
})
Expand Down
5 changes: 1 addition & 4 deletions src/dev/i18n/extract_default_translations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ describe('dev/i18n/extract_default_translations', () => {
const [, , pluginPath] = pluginsPaths;
await expect(
extractDefaultTranslations({ paths: [pluginPath], output: pluginPath })
).rejects.toMatchObject({
message: `Error in ${path.join(pluginPath, 'test_file.jsx')}
There is more than one default message for the same id "plugin_3.duplicate_id": "Message 1" and "Message 2"`,
});
).rejects.toThrowErrorMatchingSnapshot();
});

test('validates message namespace', () => {
Expand Down
35 changes: 26 additions & 9 deletions src/dev/i18n/extract_handlebars_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
* under the License.
*/

import chalk from 'chalk';

import { formatJSString } from './utils';
import { createFailError } from '../run';

const HBS_REGEX = /(?<=\{\{)([\s\S]*?)(?=\}\})/g;
const TOKENS_REGEX = /[^'\s]+|(?:'([^'\\]|\\[\s\S])*')/g;
Expand All @@ -36,42 +39,56 @@ export function* extractHandlebarsMessages(buffer) {
}

if (tokens.length !== 3) {
throw new Error('Wrong number of arguments for handlebars i18n call.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} Wrong number of arguments for handlebars i18n call.`
);
}

if (!idString.startsWith(`'`) || !idString.endsWith(`'`)) {
throw new Error('Message id should be a string literal.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} Message id should be a string literal.`
);
}

const messageId = formatJSString(idString.slice(1, -1));

if (!messageId) {
throw new Error(`Empty id argument in Handlebars i18n is not allowed.`);
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} Empty id argument in Handlebars i18n is not allowed.`
);
}

if (!propertiesString.startsWith(`'`) || !propertiesString.endsWith(`'`)) {
throw new Error(
`Properties string in Handlebars i18n should be a string literal ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Properties string in Handlebars i18n should be a string literal ("${messageId}").`
);
}

const properties = JSON.parse(propertiesString.slice(1, -1));
const message = formatJSString(properties.defaultMessage);

if (typeof message !== 'string') {
throw new Error(
`defaultMessage value in Handlebars i18n should be a string ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
defaultMessage value in Handlebars i18n should be a string ("${messageId}").`
);
}

if (!message) {
throw new Error(`Empty defaultMessage in Handlebars i18n is not allowed ("${messageId}").`);
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty defaultMessage in Handlebars i18n is not allowed ("${messageId}").`
);
}

const context = formatJSString(properties.context);

if (context != null && typeof context !== 'string') {
throw new Error(`Context value in Handlebars i18n should be a string ("${messageId}").`);
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Context value in Handlebars i18n should be a string ("${messageId}").`
);
}

yield [messageId, { message, context }];
Expand Down
35 changes: 27 additions & 8 deletions src/dev/i18n/extract_html_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
* under the License.
*/

import chalk from 'chalk';
import { jsdom } from 'jsdom';
import { parse } from '@babel/parser';
import { isDirectiveLiteral, isObjectExpression, isStringLiteral } from '@babel/types';

import { isPropertyWithKey, formatHTMLString, formatJSString, traverseNodes } from './utils';
import { DEFAULT_MESSAGE_KEY, CONTEXT_KEY } from './constants';
import { createFailError } from '../run';

/**
* Find all substrings of "{{ any text }}" pattern
Expand Down Expand Up @@ -51,13 +53,17 @@ function parseFilterObjectExpression(expression) {
for (const property of node.properties) {
if (isPropertyWithKey(property, DEFAULT_MESSAGE_KEY)) {
if (!isStringLiteral(property.value)) {
throw new Error('defaultMessage value should be a string literal.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} defaultMessage value should be a string literal.`
);
}

message = formatJSString(property.value.value);
} else if (isPropertyWithKey(property, CONTEXT_KEY)) {
if (!isStringLiteral(property.value)) {
throw new Error('context value should be a string literal.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} context value should be a string literal.`
);
}

context = formatJSString(property.value.value);
Expand Down Expand Up @@ -95,20 +101,27 @@ function* getFilterMessages(htmlContent) {
const filterObjectExpression = expression.slice(filterStart + I18N_FILTER_MARKER.length).trim();

if (!filterObjectExpression || !idExpression) {
throw new Error(`Cannot parse i18n filter expression: {{ ${expression} }}`);
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Cannot parse i18n filter expression: {{ ${expression} }}`
);
}

const messageId = parseIdExpression(idExpression);

if (!messageId) {
throw new Error('Empty "id" value in angular filter expression is not allowed.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty "id" value in angular filter expression is not allowed.`
);
}

const { message, context } = parseFilterObjectExpression(filterObjectExpression) || {};

if (!message) {
throw new Error(
`Empty defaultMessage in angular filter expression is not allowed ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty defaultMessage in angular filter expression is not allowed ("${messageId}").`
);
}

Expand All @@ -124,12 +137,18 @@ function* getDirectiveMessages(htmlContent) {
for (const element of document.querySelectorAll('[i18n-id]')) {
const messageId = formatHTMLString(element.getAttribute('i18n-id'));
if (!messageId) {
throw new Error('Empty "i18n-id" value in angular directive is not allowed.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty "i18n-id" value in angular directive is not allowed.`
);
}

const message = formatHTMLString(element.getAttribute('i18n-default-message'));
if (!message) {
throw new Error(`Empty defaultMessage in angular directive is not allowed ("${messageId}").`);
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty defaultMessage in angular directive is not allowed ("${messageId}").`
);
}

const context = formatHTMLString(element.getAttribute('i18n-context')) || undefined;
Expand Down
32 changes: 22 additions & 10 deletions src/dev/i18n/extract_i18n_call_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
* under the License.
*/

import chalk from 'chalk';
import { isObjectExpression, isStringLiteral } from '@babel/types';

import { isPropertyWithKey, formatJSString } from './utils';
import { DEFAULT_MESSAGE_KEY, CONTEXT_KEY } from './constants';
import { createFailError } from '../run';

/**
* Extract messages from `funcName('id', { defaultMessage: 'Message text' })` call expression AST
Expand All @@ -29,37 +31,46 @@ export function extractI18nCallMessages(node) {
const [idSubTree, optionsSubTree] = node.arguments;

if (!isStringLiteral(idSubTree)) {
throw new Error('Message id in i18n() or i18n.translate() should be a string literal.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Message id in i18n() or i18n.translate() should be a string literal.`
);
}

const messageId = idSubTree.value;

if (!messageId) {
throw new Error('Empty "id" value in i18n() or i18n.translate() is not allowed.');
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty "id" value in i18n() or i18n.translate() is not allowed.`
);
}

let message;
let context;

if (!isObjectExpression(optionsSubTree)) {
throw new Error(
`Empty defaultMessage in i18n() or i18n.translate() is not allowed ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty defaultMessage in i18n() or i18n.translate() is not allowed ("${messageId}").`
);
}

for (const prop of optionsSubTree.properties) {
if (isPropertyWithKey(prop, DEFAULT_MESSAGE_KEY)) {
if (!isStringLiteral(prop.value)) {
throw new Error(
`defaultMessage value in i18n() or i18n.translate() should be a string literal ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
defaultMessage value in i18n() or i18n.translate() should be a string literal ("${messageId}").`
);
}

message = formatJSString(prop.value.value);
} else if (isPropertyWithKey(prop, CONTEXT_KEY)) {
if (!isStringLiteral(prop.value)) {
throw new Error(
`context value in i18n() or i18n.translate() should be a string literal ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
context value in i18n() or i18n.translate() should be a string literal ("${messageId}").`
);
}

Expand All @@ -68,8 +79,9 @@ export function extractI18nCallMessages(node) {
}

if (!message) {
throw new Error(
`Empty defaultMessage in i18n() or i18n.translate() is not allowed ("${messageId}").`
throw createFailError(
`${chalk.white.bgRed(' I18N ERROR ')} \
Empty defaultMessage in i18n() or i18n.translate() is not allowed ("${messageId}").`
);
}

Expand Down
Loading

0 comments on commit 08f91bc

Please sign in to comment.