Skip to content

Commit

Permalink
Merge branch 'main' of github.com:elastic/kibana into add-feature-o11…
Browse files Browse the repository at this point in the history
…y-server-less
  • Loading branch information
XavierM committed Oct 30, 2023
2 parents cbc6f2f + d7ab75f commit cfb4077
Show file tree
Hide file tree
Showing 66 changed files with 2,296 additions and 1,643 deletions.
4 changes: 3 additions & 1 deletion .buildkite/ftr_configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,9 @@ enabled:
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/operators_data_types/ips_text_array/configs/ess.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/configs/serverless.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/configs/ess.config.ts

- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/serverless.config.ts
- x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/actions/configs/ess.config.ts




Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@
"archiver": "^5.3.1",
"async": "^3.2.3",
"aws4": "^1.12.0",
"axios": "^1.4.0",
"axios": "^1.6.0",
"base64-js": "^1.3.1",
"bitmap-sdf": "^1.0.3",
"blurhash": "^2.0.1",
Expand Down
12 changes: 12 additions & 0 deletions packages/kbn-eslint-plugin-i18n/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ It kicks in on JSXText elements and specific JSXAttributes (`label` and `aria-la

This rule warns engineers to translate their strings by using `<FormattedMessage>` from the '@kbn/i18n-react' package. It provides an autofix that takes into account the context of the translatable string in the JSX tree and to generate a translation ID.
It kicks in on JSXText elements and specific JSXAttributes (`label` and `aria-label`) which expect a translated value.

## Exemptions and exceptions

A JSXText element or JSXAttribute `label` or `aria-label` of which the value is:

- wrapped in a `EuiCode` or `EuiBetaBadge` component,
- made up of non alpha characters such as `!@#$%^&*(){}` or numbers,
- wrapped in three backticks,

are exempt from this rule.

If this rule kicks in on a string value that you don't like, you can escape it by wrapping the string inside a JSXExpression: `{'my escaped value'}`.
101 changes: 77 additions & 24 deletions packages/kbn-eslint-plugin-i18n/helpers/get_i18n_import_fixer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,96 @@

import { SourceCode } from 'eslint';

const KBN_I18N_I18N_IMPORT = "import { i18n } from '@kbn/i18n';" as const;
const KBN_I18N_REACT_FORMATTED_MESSAGE_IMPORT =
"import { FormattedMessage } from '@kbn/i18n-react';" as const;
export function getI18nImportFixer({
sourceCode,
mode,
}: {
sourceCode: SourceCode;
mode: 'i18n.translate' | 'FormattedMessage';
}) {
const hasI18nImportLine = Boolean(
sourceCode.lines.find((l) =>
mode === 'i18n.translate'
? l === KBN_I18N_I18N_IMPORT
: l === KBN_I18N_REACT_FORMATTED_MESSAGE_IMPORT
)
);
let existingI18nImportLineIndex = -1;
let i18nImportLineToBeAdded = '';

if (hasI18nImportLine) return { hasI18nImportLine };
/**
*
* Searching through sourcecode to see if there is already an import of i18n package,
* and check if it includes the module we need.
*
* If any of these conditions are not met, we prepare the import line we need to add.
*
* */

// Translation package has not been imported yet so we need to add it.
// Pretty safe bet to add it underneath the React import.
const reactImportLineIndex = sourceCode.lines.findIndex((l) => l.includes("from 'react'"));
if (mode === 'i18n.translate') {
existingI18nImportLineIndex = sourceCode.lines.findIndex((l) => l.includes("from '@kbn/i18n'"));

const targetLine = sourceCode.lines[reactImportLineIndex];
const column = targetLine.length;
const i18nImportLineInSource = sourceCode.lines[existingI18nImportLineIndex];

const start = sourceCode.getIndexFromLoc({ line: reactImportLineIndex + 1, column: 0 });
const end = sourceCode.getIndexFromLoc({
line: reactImportLineIndex + 1,
column,
});
if (i18nImportLineInSource) {
const modules = i18nImportLineInSource.split('{')[1].split('}')[0].trim();

if (modules.split(',').includes('i18n')) {
return { hasI18nImportLine: true };
}

// Existing import is something like: `import { SomeOtherModule } from '@kbn/i18n';`
i18nImportLineToBeAdded = `import { ${modules}, i18n } from '@kbn/i18n';`;
} else {
i18nImportLineToBeAdded = `import { i18n } from '@kbn/i18n';`;
}
}

if (mode === 'FormattedMessage') {
existingI18nImportLineIndex = sourceCode.lines.findIndex((l) =>
l.includes("from '@kbn/i18n-react'")
);
const i18nImportLineInSource = sourceCode.lines[existingI18nImportLineIndex];

if (i18nImportLineInSource) {
const modules = i18nImportLineInSource.split('{')[1].split('}')[0].trim();

if (modules.split(',').includes('FormattedMessage')) {
return { hasI18nImportLine: true };
}

// Existing import is something like: `import { SomeOtherModule } from '@kbn/i18n-react';`
i18nImportLineToBeAdded = `import { ${modules}, FormattedMessage } from '@kbn/i18n-react';`;
} else {
i18nImportLineToBeAdded = `import { FormattedMessage } from '@kbn/i18n-react';`;
}
}

/**
*
* Determining where in the source code to add the import line.
*
* */

// If the file already has an import line for the translation package but it doesn't include the module we need, we need to add it.
if (existingI18nImportLineIndex > -1) {
const targetLine = sourceCode.lines[existingI18nImportLineIndex];
const column = targetLine.length;

const start = sourceCode.getIndexFromLoc({ line: existingI18nImportLineIndex + 1, column: 0 });
const end = start + column;

return {
i18nImportLine: i18nImportLineToBeAdded,
rangeToAddI18nImportLine: [start, end] as [number, number],
mode: 'replace',
};
}

// If the file doesn't have an import line for the translation package yet, we need to add it.
// Pretty safe bet to add it underneath the import line for React.
const lineIndex = sourceCode.lines.findIndex((l) => l.includes("from 'react'"));
const targetLine = sourceCode.lines[lineIndex];

const start = sourceCode.getIndexFromLoc({ line: lineIndex + 1, column: 0 });
const end = start + targetLine.length;

return {
hasI18nImportLine,
i18nPackageImportLine:
mode === 'i18n.translate' ? KBN_I18N_I18N_IMPORT : KBN_I18N_REACT_FORMATTED_MESSAGE_IMPORT,
i18nImportLine: i18nImportLineToBeAdded,
rangeToAddI18nImportLine: [start, end] as [number, number],
mode: 'insert',
};
}
24 changes: 18 additions & 6 deletions packages/kbn-eslint-plugin-i18n/helpers/get_intent_from_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
* Side Public License, v 1.
*/
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/typescript-estree';
import { lowerCaseFirstLetter, upperCaseFirstLetter } from './utils';
import { cleanString, lowerCaseFirstLetter, upperCaseFirstLetter } from './utils';

export function getIntentFromNode(value: string, parent: TSESTree.Node | undefined): string {
const EXEMPTED_TAG_NAMES = ['EuiCode', 'EuiBetaBadge', 'FormattedMessage'];

export function getIntentFromNode(
value: string,
parent: TSESTree.Node | undefined
): string | false {
const processedValue = lowerCaseFirstLetter(
value
.replace(/[?!@#$%^&*()_+\][{}|/<>,'"]/g, '')
.trim()
cleanString(value)
.split(' ')
.filter((v, i) => i < 4)
.filter((_, i) => i < 4)
.map(upperCaseFirstLetter)
.join('')
);
Expand All @@ -27,6 +30,11 @@ export function getIntentFromNode(value: string, parent: TSESTree.Node | undefin
) {
const parentTagName = String(parent.openingElement.name.name);

// Exceptions
if (EXEMPTED_TAG_NAMES.includes(parentTagName)) {
return false;
}

if (parentTagName.includes('Eui')) {
return `${processedValue}${parentTagName.replace('Eui', '')}Label`;
}
Expand All @@ -45,6 +53,10 @@ export function getIntentFromNode(value: string, parent: TSESTree.Node | undefin
) {
const parentTagName = String(parent.parent.name.name);

if (EXEMPTED_TAG_NAMES.includes(parentTagName)) {
return false;
}

return `${lowerCaseFirstLetter(parentTagName)}.${processedValue}Label`;
}

Expand Down
55 changes: 55 additions & 0 deletions packages/kbn-eslint-plugin-i18n/helpers/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { cleanString, lowerCaseFirstLetter } from './utils';

describe('Utils', () => {
describe('lowerCaseFirstLetter', () => {
it('should lowercase the first letter', () => {
expect(lowerCaseFirstLetter('Hello')).toBe('hello');
expect(lowerCaseFirstLetter('GreatSuccessYes')).toBe('greatSuccessYes');
expect(lowerCaseFirstLetter('How is it going?')).toBe('how is it going?');
});

it('should lowercase all letters if the passed string is in ALL CAPS', () => {
expect(lowerCaseFirstLetter('HELLO')).toBe('hello');
expect(lowerCaseFirstLetter('GREATSUCCESSYES')).toBe('greatsuccessyes');
});
});

describe('cleanString', () => {
it('should remove all numbers', () => {
expect(cleanString('123')).toBe('');
});

it('should remove all white spaces from beginning and end', () => {
expect(cleanString(' abc ')).toBe('abc');
expect(cleanString(' This is a test ')).toBe('This is a test');
expect(
cleanString(`
hello
great!`)
).toBe('hello great');
});

it('should remove all non alphabet characters', () => {
expect(cleanString('abc123!@#')).toBe('abc');
expect(cleanString('!@#$%^&*()_+{}|')).toBe('');
expect(cleanString(' Hey, this is great! Success. ')).toBe('Hey this is great Success');
});

it('should leave markdown alone', () => {
expect(cleanString('```hello```')).toBe('');
});
});
});
14 changes: 14 additions & 0 deletions packages/kbn-eslint-plugin-i18n/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*/

export function lowerCaseFirstLetter(str: string) {
if (isUpperCase(str)) return str.toLowerCase();

return str.charAt(0).toLowerCase() + str.slice(1);
}

Expand All @@ -17,3 +19,15 @@ export function upperCaseFirstLetter(str: string) {
export function isTruthy<T>(value: T): value is NonNullable<T> {
return value != null;
}

function isUpperCase(val: string) {
return /^[A-Z]+$/.test(val);
}

export function cleanString(str: string) {
return str
.replace(/```\w*```/g, '')
.replace(/\s+/g, ' ')
.replace(/[^a-zA-Z\s]*/g, '')
.trim();
}
Loading

0 comments on commit cfb4077

Please sign in to comment.