Skip to content

Commit

Permalink
backport elastic#205011
Browse files Browse the repository at this point in the history
  • Loading branch information
tkajtoch committed Jan 10, 2025
1 parent 8787073 commit 6a533ff
Show file tree
Hide file tree
Showing 16 changed files with 291 additions and 0 deletions.
1 change: 1 addition & 0 deletions .buildkite/scripts/steps/checks/quick_checks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
.buildkite/scripts/steps/checks/prettier_topology.sh
.buildkite/scripts/steps/checks/renovate.sh
.buildkite/scripts/steps/checks/native_modules.sh
.buildkite/scripts/steps/checks/styled_components_mapping.sh
11 changes: 11 additions & 0 deletions .buildkite/scripts/steps/checks/styled_components_mapping.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

set -euo pipefail

source .buildkite/scripts/common/util.sh

echo --- Check styled-components mapping
cmd="node scripts/styled_components_mapping"

eval "$cmd"
check_for_changed_files "$cmd" true
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@ src/platform/packages/shared/kbn-xstate-utils @elastic/obs-ux-logs-team
packages/kbn-yarn-lock-validator @elastic/kibana-operations
src/platform/packages/shared/kbn-zod @elastic/kibana-core
src/platform/packages/shared/kbn-zod-helpers @elastic/security-detection-rule-management
packages/kbn-styled-components-mapping-cli @elastic/kibana-operations @elastic/eui-team
####
## Everything below this line overrides the default assignments for each package.
## Items lower in the file have higher precedence:
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,7 @@
"@kbn/spec-to-console": "link:packages/kbn-spec-to-console",
"@kbn/stdio-dev-helpers": "link:packages/kbn-stdio-dev-helpers",
"@kbn/storybook": "link:packages/kbn-storybook",
"@kbn/styled-components-mapping-cli": "link:packages/kbn-styled-components-mapping-cli",
"@kbn/synthetics-e2e": "link:x-pack/solutions/observability/plugins/synthetics/e2e",
"@kbn/synthetics-private-location": "link:x-pack/packages/kbn-synthetics-private-location",
"@kbn/telemetry-tools": "link:packages/kbn-telemetry-tools",
Expand Down
10 changes: 10 additions & 0 deletions packages/kbn-styled-components-mapping-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# @kbn/styled-components-mapping-cli

A helper tool that looks up components using `styled-components` and generates
a mapping file for Babel to help with proper stylesheet loading.

## Usage

```shell
node scripts/styled_components_mapping
```
14 changes: 14 additions & 0 deletions packages/kbn-styled-components-mapping-cli/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-styled-components-mapping-cli'],
};
6 changes: 6 additions & 0 deletions packages/kbn-styled-components-mapping-cli/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "shared-common",
"id": "@kbn/styled-components-mapping-cli",
"owner": ["@elastic/kibana-operations", "@elastic/eui-team"],
"devOnly": true
}
7 changes: 7 additions & 0 deletions packages/kbn-styled-components-mapping-cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@kbn/styled-components-mapping-cli",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0",
"main": "./src/run_styled_components_mapping_cli.ts"
}
79 changes: 79 additions & 0 deletions packages/kbn-styled-components-mapping-cli/src/find_files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as fs from 'node:fs/promises';
import * as path from 'node:path';

const SOURCE_DIRS = ['x-pack', 'src', 'packages'];
const SOURCE_FILE_REGEX = /(^.?|\.[^d]|[^.]d|[^.][^d])\.tsx?$/;
const STYLED_COMPONENTS_IMPORT_REGEX =
/import\s+(?:{[^{}]+}|.*?)\s*(?:from)?\s*['"](styled-components)['"]/;
const EMOTION_STYLED_IMPORT_REGEX =
/import\s+(?:{[^{}]+}|.*?)\s*(?:from)?\s*['"](@emotion\/styled)['"]/;

export interface Meta {
path: string;
usesStyledComponents: boolean;
usesOnlyStyledComponents?: boolean;
files?: Meta[];
}

const walkDirectory = async (dirPath: string): Promise<Meta> => {
const files: Meta[] = [];
let usesStyledComponents = false;
let usesOnlyStyledComponents = true;

for (const file of await fs.readdir(dirPath, { withFileTypes: true })) {
const fullPath = path.join(file.path, file.name);

if (file.isDirectory()) {
const meta = await walkDirectory(fullPath);
if (meta.usesStyledComponents) {
usesStyledComponents = true;
}
if (usesOnlyStyledComponents && !meta.usesOnlyStyledComponents) {
usesOnlyStyledComponents = false;
}
files.push(meta);
continue;
}

if (!SOURCE_FILE_REGEX.test(file.name) || !file.isFile()) {
continue;
}

const meta: Meta = {
path: fullPath,
usesStyledComponents: false,
};

const contents = await fs.readFile(fullPath, 'utf8');
const usesEmotionStyled = EMOTION_STYLED_IMPORT_REGEX.test(contents);
meta.usesStyledComponents = STYLED_COMPONENTS_IMPORT_REGEX.test(contents);

if (usesEmotionStyled) {
usesOnlyStyledComponents = false;
}

if (usesEmotionStyled || meta.usesStyledComponents) {
files.push(meta);
}
}

return {
path: dirPath,
files,
usesStyledComponents,
usesOnlyStyledComponents: usesStyledComponents && usesOnlyStyledComponents,
};
};

export const findFiles = async (rootDirPath: string) => {
return Promise.all(SOURCE_DIRS.map((dir) => walkDirectory(path.join(rootDirPath, dir))));
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as path from 'node:path';
import type { Meta } from './find_files';

export const pathToRegexString = (modulePath: string): string => {
modulePath = modulePath.replace(/[\\\/]/g, '[\\/\\\\]');

return `/${modulePath}/`;
};

export const generateRegexStringArray = (files: Meta[], rootDirPath: string): string[] => {
const array: string[] = [];

for (const meta of files) {
if (meta.files) {
if (meta.usesOnlyStyledComponents) {
array.push(pathToRegexString(path.relative(rootDirPath, meta.path)));
} else {
array.push(...generateRegexStringArray(meta.files, rootDirPath));
}
} else if (meta.usesStyledComponents) {
array.push(pathToRegexString(path.relative(rootDirPath, meta.path)));
}
}

return array;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as path from 'node:path';
import { run } from '@kbn/dev-cli-runner';
import { createFailError } from '@kbn/dev-cli-errors';
import { REPO_ROOT } from '@kbn/repo-info';
import { findFiles } from './find_files';
import { generateRegexStringArray } from './generate_regex_array';
import { updateFile } from './update_file';

const mappingFilePath = 'packages/kbn-babel-preset/styled_components_files.js';
const mappingFileAbsolutePath = path.join(REPO_ROOT, mappingFilePath);

run(
async ({ log }) => {
log.info(`Looking for source files importing 'styled-components'...`);

const files = await findFiles(REPO_ROOT);
const regexStringArray = generateRegexStringArray(files, REPO_ROOT);

try {
await updateFile(mappingFileAbsolutePath, regexStringArray);
} catch (err) {
createFailError(err);
}

log.info(`Generated ${mappingFilePath} with ${regexStringArray.length} regex expressions`);
},
{
usage: `node scripts/styled_components_mapping`,
description: 'Update styled-components babel mapping when converting styles to Emotion',
}
);
48 changes: 48 additions & 0 deletions packages/kbn-styled-components-mapping-cli/src/update_file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import * as fs from 'node:fs/promises';

const babelFilePrefix = `/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
module.exports = {
/**
* Synchronized list of all source files that use styled-components.
* Please keep this list up-to-date when converting component styles
* from styled-components to Emotion.
*
* Babel's MatchPattern can be a regex or a string which follows standard
* Node.js path logic as described here:
* https://babeljs.io/docs/options#matchpattern
*
* Used by \`kbn-babel-preset\` and \`kbn-eslint-config\`.
*/
USES_STYLED_COMPONENTS: [
/packages[\\/\\\\]kbn-ui-shared-deps-npm[\\/\\\\]/,
/packages[\\/\\\\]kbn-ui-shared-deps-src[\\/\\\\]/,
`;

const babelFileSuffix = ` ],
};
`;

export const updateFile = async (filePath: string, regexStringArray: string[]) => {
const contents = `${babelFilePrefix}\n ${regexStringArray.join(
',\n '
)},\n${babelFileSuffix}`;

return fs.writeFile(filePath, contents);
};
21 changes: 21 additions & 0 deletions packages/kbn-styled-components-mapping-cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/dev-cli-runner",
"@kbn/dev-cli-errors",
"@kbn/repo-info",
]
}
11 changes: 11 additions & 0 deletions scripts/styled_components_mapping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

require('../src/setup_node_env');
require('@kbn/styled-components-mapping-cli');
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1878,6 +1878,8 @@
"@kbn/streams-plugin/*": ["x-pack/solutions/observability/plugins/streams/*"],
"@kbn/streams-schema": ["x-pack/packages/kbn-streams-schema"],
"@kbn/streams-schema/*": ["x-pack/packages/kbn-streams-schema/*"],
"@kbn/styled-components-mapping-cli": ["packages/kbn-styled-components-mapping-cli"],
"@kbn/styled-components-mapping-cli/*": ["packages/kbn-styled-components-mapping-cli/*"],
"@kbn/synthetics-e2e": ["x-pack/solutions/observability/plugins/synthetics/e2e"],
"@kbn/synthetics-e2e/*": ["x-pack/solutions/observability/plugins/synthetics/e2e/*"],
"@kbn/synthetics-plugin": ["x-pack/solutions/observability/plugins/synthetics"],
Expand Down
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7608,6 +7608,10 @@
version "0.0.0"
uid ""

"@kbn/styled-components-mapping-cli@link:packages/kbn-styled-components-mapping-cli":
version "0.0.0"
uid ""

"@kbn/synthetics-e2e@link:x-pack/solutions/observability/plugins/synthetics/e2e":
version "0.0.0"
uid ""
Expand Down

0 comments on commit 6a533ff

Please sign in to comment.