"eslint-plugin-import": "2.27.5",
"eslint-plugin-local-rules": "1.3.2",
"eslint-plugin-typescript-sort-keys": "2.3.0",
+ "highlight.js": "11.7.0",
"history": "5.3.0",
"jest": "29.5.0",
"postcss": "8.4.21",
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import classNames from 'classnames';
+import tw from 'twin.macro';
+import { themeBorder, themeColor } from '../helpers/theme';
+import { isDefined } from '../helpers/types';
+import { Highlighter, RegisteredLanguages } from './Highlighter';
+import { ClipboardButton } from './clipboard';
+
+interface Props {
+ className?: string;
+ highlight?: boolean;
+ isOneLine?: boolean;
+ join?: string;
+ language?: RegisteredLanguages;
+ noCopy?: boolean;
+ render?: string;
+ snippet: string | Array<string | undefined>;
+ toggleEdit?: VoidFunction;
+ wrap?: boolean;
+}
+
+// keep this "useless" concatenation for the readability reason
+// eslint-disable-next-line no-useless-concat
+const s = ' \\' + '\n ';
+
+export function CodeSnippet(props: Props) {
+ const {
+ className,
+ isOneLine,
+ highlight,
+ join = s,
+ language,
+ noCopy,
+ render,
+ snippet,
+ toggleEdit,
+ wrap,
+ } = props;
+ const snippetArray = Array.isArray(snippet) ? snippet.filter(isDefined) : [snippet];
+ const finalSnippet = isOneLine ? snippetArray.join(' ') : snippetArray.join(join);
+
+ const isSimpleOneLine = isOneLine && noCopy;
+
+ const copyButton = isOneLine ? (
+ <StyledSingleLineClipboardButton copyValue={finalSnippet} />
+ ) : (
+ <StyledClipboardButton copyValue={finalSnippet} />
+ );
+
+ return (
+ <Wrapper
+ className={classNames(
+ {
+ 'code-snippet-highlighted-oneline': isOneLine,
+ 'code-snippet-simple-oneline': isSimpleOneLine,
+ },
+ className,
+ 'fs-mask'
+ )}
+ >
+ {!noCopy && copyButton}
+ <Highlighter
+ code={render ?? finalSnippet}
+ highlight={highlight}
+ isSimpleOneLine={isSimpleOneLine}
+ language={language}
+ toggleEdit={isOneLine ? toggleEdit : undefined}
+ wrap={wrap}
+ />
+ </Wrapper>
+ );
+}
+
+const Wrapper = styled.div`
+ background-color: ${themeColor('codeSnippetBackground')};
+ border: ${themeBorder('default', 'codeSnippetBorder')};
+
+ ${tw`sw-rounded-2`}
+ ${tw`sw-relative`}
+ ${tw`sw-my-2`}
+
+ &.code-snippet-simple-oneline {
+ ${tw`sw-my-0`}
+ ${tw`sw-rounded-1`}
+ }
+`;
+
+const StyledClipboardButton = styled(ClipboardButton)`
+ ${tw`sw-select-none`}
+ ${tw`sw-body-sm`}
+ ${tw`sw-top-6 sw-right-6`}
+ ${tw`sw-absolute`}
+
+ .code-snippet-highlighted-oneline & {
+ ${tw`sw-bottom-2`}
+ }
+`;
+
+const StyledSingleLineClipboardButton = styled(StyledClipboardButton)`
+ ${tw`sw-top-6 sw-bottom-6`}
+`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import styled from '@emotion/styled';
+import classNames from 'classnames';
+import hljs from 'highlight.js/lib/core';
+import bash from 'highlight.js/lib/languages/bash';
+import gradle from 'highlight.js/lib/languages/gradle';
+import plaintext from 'highlight.js/lib/languages/plaintext';
+import powershell from 'highlight.js/lib/languages/powershell';
+import properties from 'highlight.js/lib/languages/properties';
+import shell from 'highlight.js/lib/languages/shell';
+import xml from 'highlight.js/lib/languages/xml';
+import yaml from 'highlight.js/lib/languages/yaml';
+import { useMemo } from 'react';
+import tw from 'twin.macro';
+import { translate } from '../helpers/l10n';
+import { themeColor, themeContrast } from '../helpers/theme';
+import { InteractiveIcon } from './InteractiveIcon';
+import { PencilIcon } from './icons';
+
+hljs.registerLanguage('yaml', yaml);
+hljs.registerLanguage('gradle', gradle);
+hljs.registerLanguage('properties', properties);
+hljs.registerLanguage('xml', xml);
+hljs.registerLanguage('bash', bash);
+hljs.registerLanguage('powershell', powershell);
+hljs.registerLanguage('shell', shell);
+hljs.registerLanguage('plaintext', plaintext);
+
+hljs.addPlugin({
+ 'after:highlight': (data) => {
+ data.value = data.value
+ .replace(/<mark>/g, '<mark>')
+ .replace(/<\/mark>/g, '</mark>');
+ },
+});
+
+export type RegisteredLanguages =
+ | 'bash'
+ | 'gradle'
+ | 'plaintext'
+ | 'powershell'
+ | 'properties'
+ | 'shell'
+ | 'xml'
+ | 'yaml';
+
+interface Props {
+ className?: string;
+ code: string;
+ highlight?: boolean;
+ isSimpleOneLine?: boolean;
+ language?: RegisteredLanguages;
+ toggleEdit?: VoidFunction;
+ wrap?: boolean;
+}
+
+export function Highlighter({
+ className,
+ code,
+ highlight = true,
+ isSimpleOneLine = false,
+ language = 'yaml',
+ toggleEdit,
+ wrap,
+}: Props) {
+ const highlighted = useMemo(
+ () => hljs.highlight(code, { language: highlight ? language : 'plaintext' }),
+ [code, highlight, language]
+ );
+
+ return (
+ <StyledPre
+ className={classNames({ 'code-wrap': wrap, 'simple-one-line': isSimpleOneLine }, className)}
+ >
+ <code
+ className={classNames('hljs', { 'sw-inline': toggleEdit })}
+ // Safe: value is escaped by highlight.js
+ // eslint-disable-next-line react/no-danger
+ dangerouslySetInnerHTML={{ __html: highlighted.value }}
+ />
+ {toggleEdit && (
+ <InteractiveIcon
+ Icon={PencilIcon}
+ aria-label={translate('edit')}
+ className="sw-ml-2"
+ onClick={toggleEdit}
+ />
+ )}
+ </StyledPre>
+ );
+}
+
+const StyledPre = styled.pre`
+ ${tw`sw-flex sw-items-center`}
+ ${tw`sw-overflow-x-auto`}
+ ${tw`sw-p-6`}
+
+ code {
+ color: ${themeColor('codeSnippetBody')};
+ background: ${themeColor('codeSnippetBackground')};
+ ${tw`sw-code`};
+
+ &.hljs {
+ padding: unset;
+ }
+ }
+
+ .hljs-variable,
+ .hljs-meta {
+ color: ${themeColor('codeSnippetBody')};
+ }
+
+ .hljs-doctag,
+ .hljs-title,
+ .hljs-title.class_,
+ .hljs-title.function_ {
+ color: ${themeColor('codeSnippetAnnotations')};
+ }
+
+ .hljs-comment {
+ color: ${themeColor('codeSnippetComments')};
+
+ ${tw`sw-code-comment`}
+ }
+
+ .hljs-tag,
+ .hljs-type,
+ .hljs-keyword {
+ color: ${themeColor('codeSnippetKeyword')};
+
+ ${tw`sw-code-highlight`}
+ }
+
+ .hljs-literal,
+ .hljs-number {
+ color: ${themeColor('codeSnippetConstants')};
+ }
+
+ .hljs-string {
+ color: ${themeColor('codeSnippetString')};
+ }
+
+ .hljs-meta .hljs-keyword {
+ color: ${themeColor('codeSnippetPreprocessingDirective')};
+ }
+
+ &.code-wrap {
+ ${tw`sw-whitespace-pre-wrap`}
+ ${tw`sw-break-all`}
+ }
+
+ mark {
+ color: ${themeContrast('codeSnippetHighlight')};
+ background-color: ${themeColor('codeSnippetHighlight')};
+ ${tw`sw-font-regular`}
+ ${tw`sw-rounded-1`}
+ ${tw`sw-p-1`}
+ }
+
+ &.simple-one-line {
+ ${tw`sw-min-h-[1.25rem]`}
+ ${tw`sw-py-0 sw-px-1`}
+ }
+`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { screen } from '@testing-library/react';
+import { HelmetProvider } from 'react-helmet-async';
+import { renderWithContext } from '../../helpers/testUtils';
+import { FCProps } from '../../types/misc';
+import { CodeSnippet } from '../CodeSnippet';
+
+it('should show full size when multiline with no editting', () => {
+ const { container } = setupWithProps();
+ const copyButton = screen.getByRole('button', { name: 'copy' });
+ expect(copyButton).toHaveStyle('top: 1.5rem');
+ expect(container).toMatchSnapshot();
+});
+
+it('should show reduced size when single line with no editting', () => {
+ const { container } = setupWithProps({ isOneLine: true, snippet: 'foobar' });
+ const copyButton = screen.getByRole('button', { name: 'copy' });
+ expect(copyButton).toHaveStyle('top: 1.5rem');
+ expect(container).toMatchSnapshot();
+});
+
+function setupWithProps(props: Partial<FCProps<typeof CodeSnippet>> = {}) {
+ return renderWithContext(
+ <HelmetProvider>
+ <CodeSnippet snippet={'foo\nbar'} {...props} />
+ </HelmetProvider>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import { renderWithContext } from '../../helpers/testUtils';
+import { FCProps } from '../../types/misc';
+import { Highlighter } from '../Highlighter';
+
+it('renders correctly', () => {
+ expect(setupWithProps().container).toMatchSnapshot();
+});
+
+it('should handle multiple lines of code', () => {
+ expect(
+ setupWithProps({
+ code: `foo: bar
+ pleh: help
+ stuff:
+ foo: bar
+ bar: foo`,
+ language: 'yaml',
+ }).container
+ ).toMatchSnapshot();
+});
+
+it('should display edit functions', () => {
+ expect(
+ setupWithProps({ code: 'One line command', toggleEdit: jest.fn() }).container
+ ).toMatchSnapshot();
+});
+
+function setupWithProps(props: Partial<FCProps<typeof Highlighter>> = {}) {
+ return renderWithContext(<Highlighter code="foo\nbar" {...props} />);
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should show full size when multiline with no editting 1`] = `
+.emotion-0 {
+ background-color: rgb(252,252,253);
+ border: 1px solid rgb(225,230,243);
+ border-radius: 0.5rem;
+ position: relative;
+ margin-top: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.emotion-0.code-snippet-simple-oneline {
+ margin-top: 0;
+ margin-bottom: 0;
+ border-radius: 0.25rem;
+}
+
+.emotion-4 {
+ box-sizing: border-box;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ outline: none;
+ border: var(--border);
+ color: var(--color);
+ background-color: var(--background);
+ -webkit-transition: background-color 0.2s ease,outline 0.2s ease;
+ transition: background-color 0.2s ease,outline 0.2s ease;
+ display: -webkit-inline-box;
+ display: -webkit-inline-flex;
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ height: 2.25rem;
+ font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 600;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ border-radius: 0.5rem;
+ cursor: pointer;
+ --background: rgb(255,255,255);
+ --backgroundHover: rgb(239,242,249);
+ --color: rgb(62,67,87);
+ --focus: rgba(197,205,223,0.2);
+ --border: 1px solid rgb(197,205,223);
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+ right: 1.5rem;
+ top: 1.5rem;
+ position: absolute;
+}
+
+.emotion-4:hover {
+ color: var(--color);
+ background-color: var(--backgroundHover);
+}
+
+.emotion-4:focus,
+.emotion-4:active {
+ color: var(--color);
+ outline: 4px solid var(--focus);
+}
+
+.emotion-4:disabled,
+.emotion-4:disabled:hover {
+ color: rgb(166,173,194);
+ background-color: rgb(239,242,249);
+ border: 1px solid rgb(197,205,223);
+ cursor: not-allowed;
+}
+
+.emotion-4>svg {
+ margin-right: 0.25rem;
+}
+
+.emotion-4 [disabled] {
+ pointer-events: none;
+}
+
+.code-snippet-highlighted-oneline .emotion-4 {
+ bottom: 0.5rem;
+}
+
+.emotion-6 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ overflow-x: auto;
+ padding: 1.5rem;
+}
+
+.emotion-6 code {
+ color: rgb(51,53,60);
+ background: rgb(252,252,253);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+}
+
+.emotion-6 code.hljs {
+ padding: unset;
+}
+
+.emotion-6 .hljs-variable,
+.emotion-6 .hljs-meta {
+ color: rgb(51,53,60);
+}
+
+.emotion-6 .hljs-doctag,
+.emotion-6 .hljs-title,
+.emotion-6 .hljs-title.class_,
+.emotion-6 .hljs-title.function_ {
+ color: rgb(34,84,192);
+}
+
+.emotion-6 .hljs-comment {
+ color: rgb(109,111,119);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-style: italic;
+}
+
+.emotion-6 .hljs-tag,
+.emotion-6 .hljs-type,
+.emotion-6 .hljs-keyword {
+ color: rgb(152,29,150);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 700;
+}
+
+.emotion-6 .hljs-literal,
+.emotion-6 .hljs-number {
+ color: rgb(126,83,5);
+}
+
+.emotion-6 .hljs-string {
+ color: rgb(32,105,31);
+}
+
+.emotion-6 .hljs-meta .hljs-keyword {
+ color: rgb(47,103,48);
+}
+
+.emotion-6.code-wrap {
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+.emotion-6 mark {
+ color: rgb(217,45,32);
+ background-color: rgb(197,205,223);
+ font-weight: 400;
+ border-radius: 0.25rem;
+ padding: 0.25rem;
+}
+
+.emotion-6.simple-one-line {
+ min-height: 1.25rem;
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+<div>
+ <div
+ class="fs-mask emotion-0 emotion-1"
+ >
+ <button
+ class="sw-select-none emotion-2 emotion-3 emotion-4 emotion-5"
+ data-clipboard-text="foo
+bar"
+ type="button"
+ >
+ <svg
+ aria-hidden="true"
+ class="octicon octicon-copy"
+ fill="currentColor"
+ focusable="false"
+ height="16"
+ role="img"
+ style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
+ viewBox="0 0 16 16"
+ width="16"
+ >
+ <path
+ d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"
+ />
+ <path
+ d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
+ />
+ </svg>
+ copy
+ </button>
+ <pre
+ class=" emotion-6 emotion-7"
+ >
+ <code
+ class="hljs"
+ >
+ <span
+ class="hljs-string"
+ >
+ foo
+ </span>
+
+
+ <span
+ class="hljs-string"
+ >
+ bar
+ </span>
+ </code>
+ </pre>
+ </div>
+</div>
+`;
+
+exports[`should show reduced size when single line with no editting 1`] = `
+.emotion-0 {
+ background-color: rgb(252,252,253);
+ border: 1px solid rgb(225,230,243);
+ border-radius: 0.5rem;
+ position: relative;
+ margin-top: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.emotion-0.code-snippet-simple-oneline {
+ margin-top: 0;
+ margin-bottom: 0;
+ border-radius: 0.25rem;
+}
+
+.emotion-4 {
+ box-sizing: border-box;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ outline: none;
+ border: var(--border);
+ color: var(--color);
+ background-color: var(--background);
+ -webkit-transition: background-color 0.2s ease,outline 0.2s ease;
+ transition: background-color 0.2s ease,outline 0.2s ease;
+ display: -webkit-inline-box;
+ display: -webkit-inline-flex;
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ height: 2.25rem;
+ font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 600;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+ border-radius: 0.5rem;
+ cursor: pointer;
+ --background: rgb(255,255,255);
+ --backgroundHover: rgb(239,242,249);
+ --color: rgb(62,67,87);
+ --focus: rgba(197,205,223,0.2);
+ --border: 1px solid rgb(197,205,223);
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+ right: 1.5rem;
+ top: 1.5rem;
+ position: absolute;
+ bottom: 1.5rem;
+ top: 1.5rem;
+}
+
+.emotion-4:hover {
+ color: var(--color);
+ background-color: var(--backgroundHover);
+}
+
+.emotion-4:focus,
+.emotion-4:active {
+ color: var(--color);
+ outline: 4px solid var(--focus);
+}
+
+.emotion-4:disabled,
+.emotion-4:disabled:hover {
+ color: rgb(166,173,194);
+ background-color: rgb(239,242,249);
+ border: 1px solid rgb(197,205,223);
+ cursor: not-allowed;
+}
+
+.emotion-4>svg {
+ margin-right: 0.25rem;
+}
+
+.emotion-4 [disabled] {
+ pointer-events: none;
+}
+
+.code-snippet-highlighted-oneline .emotion-4 {
+ bottom: 0.5rem;
+}
+
+.emotion-6 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ overflow-x: auto;
+ padding: 1.5rem;
+}
+
+.emotion-6 code {
+ color: rgb(51,53,60);
+ background: rgb(252,252,253);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+}
+
+.emotion-6 code.hljs {
+ padding: unset;
+}
+
+.emotion-6 .hljs-variable,
+.emotion-6 .hljs-meta {
+ color: rgb(51,53,60);
+}
+
+.emotion-6 .hljs-doctag,
+.emotion-6 .hljs-title,
+.emotion-6 .hljs-title.class_,
+.emotion-6 .hljs-title.function_ {
+ color: rgb(34,84,192);
+}
+
+.emotion-6 .hljs-comment {
+ color: rgb(109,111,119);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-style: italic;
+}
+
+.emotion-6 .hljs-tag,
+.emotion-6 .hljs-type,
+.emotion-6 .hljs-keyword {
+ color: rgb(152,29,150);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 700;
+}
+
+.emotion-6 .hljs-literal,
+.emotion-6 .hljs-number {
+ color: rgb(126,83,5);
+}
+
+.emotion-6 .hljs-string {
+ color: rgb(32,105,31);
+}
+
+.emotion-6 .hljs-meta .hljs-keyword {
+ color: rgb(47,103,48);
+}
+
+.emotion-6.code-wrap {
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+.emotion-6 mark {
+ color: rgb(217,45,32);
+ background-color: rgb(197,205,223);
+ font-weight: 400;
+ border-radius: 0.25rem;
+ padding: 0.25rem;
+}
+
+.emotion-6.simple-one-line {
+ min-height: 1.25rem;
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+<div>
+ <div
+ class="code-snippet-highlighted-oneline fs-mask emotion-0 emotion-1"
+ >
+ <button
+ class="sw-select-none emotion-2 emotion-3 emotion-4 emotion-5"
+ data-clipboard-text="foobar"
+ type="button"
+ >
+ <svg
+ aria-hidden="true"
+ class="octicon octicon-copy"
+ fill="currentColor"
+ focusable="false"
+ height="16"
+ role="img"
+ style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
+ viewBox="0 0 16 16"
+ width="16"
+ >
+ <path
+ d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"
+ />
+ <path
+ d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
+ />
+ </svg>
+ copy
+ </button>
+ <pre
+ class=" emotion-6 emotion-7"
+ >
+ <code
+ class="hljs"
+ >
+ <span
+ class="hljs-string"
+ >
+ foobar
+ </span>
+ </code>
+ </pre>
+ </div>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+.emotion-0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ overflow-x: auto;
+ padding: 1.5rem;
+}
+
+.emotion-0 code {
+ color: rgb(51,53,60);
+ background: rgb(252,252,253);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+}
+
+.emotion-0 code.hljs {
+ padding: unset;
+}
+
+.emotion-0 .hljs-variable,
+.emotion-0 .hljs-meta {
+ color: rgb(51,53,60);
+}
+
+.emotion-0 .hljs-doctag,
+.emotion-0 .hljs-title,
+.emotion-0 .hljs-title.class_,
+.emotion-0 .hljs-title.function_ {
+ color: rgb(34,84,192);
+}
+
+.emotion-0 .hljs-comment {
+ color: rgb(109,111,119);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-style: italic;
+}
+
+.emotion-0 .hljs-tag,
+.emotion-0 .hljs-type,
+.emotion-0 .hljs-keyword {
+ color: rgb(152,29,150);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 700;
+}
+
+.emotion-0 .hljs-literal,
+.emotion-0 .hljs-number {
+ color: rgb(126,83,5);
+}
+
+.emotion-0 .hljs-string {
+ color: rgb(32,105,31);
+}
+
+.emotion-0 .hljs-meta .hljs-keyword {
+ color: rgb(47,103,48);
+}
+
+.emotion-0.code-wrap {
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+.emotion-0 mark {
+ color: rgb(217,45,32);
+ background-color: rgb(197,205,223);
+ font-weight: 400;
+ border-radius: 0.25rem;
+ padding: 0.25rem;
+}
+
+.emotion-0.simple-one-line {
+ min-height: 1.25rem;
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+<div>
+ <pre
+ class=" emotion-0 emotion-1"
+ >
+ <code
+ class="hljs"
+ >
+ <span
+ class="hljs-string"
+ >
+ foo\\nbar
+ </span>
+ </code>
+ </pre>
+</div>
+`;
+
+exports[`should display edit functions 1`] = `
+.emotion-0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ overflow-x: auto;
+ padding: 1.5rem;
+}
+
+.emotion-0 code {
+ color: rgb(51,53,60);
+ background: rgb(252,252,253);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+}
+
+.emotion-0 code.hljs {
+ padding: unset;
+}
+
+.emotion-0 .hljs-variable,
+.emotion-0 .hljs-meta {
+ color: rgb(51,53,60);
+}
+
+.emotion-0 .hljs-doctag,
+.emotion-0 .hljs-title,
+.emotion-0 .hljs-title.class_,
+.emotion-0 .hljs-title.function_ {
+ color: rgb(34,84,192);
+}
+
+.emotion-0 .hljs-comment {
+ color: rgb(109,111,119);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-style: italic;
+}
+
+.emotion-0 .hljs-tag,
+.emotion-0 .hljs-type,
+.emotion-0 .hljs-keyword {
+ color: rgb(152,29,150);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 700;
+}
+
+.emotion-0 .hljs-literal,
+.emotion-0 .hljs-number {
+ color: rgb(126,83,5);
+}
+
+.emotion-0 .hljs-string {
+ color: rgb(32,105,31);
+}
+
+.emotion-0 .hljs-meta .hljs-keyword {
+ color: rgb(47,103,48);
+}
+
+.emotion-0.code-wrap {
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+.emotion-0 mark {
+ color: rgb(217,45,32);
+ background-color: rgb(197,205,223);
+ font-weight: 400;
+ border-radius: 0.25rem;
+ padding: 0.25rem;
+}
+
+.emotion-0.simple-one-line {
+ min-height: 1.25rem;
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+.emotion-3 {
+ box-sizing: border-box;
+ border: none;
+ outline: none;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+ color: var(--color);
+ background-color: var(--background);
+ -webkit-transition: background-color 0.2s ease,outline 0.2s ease,color 0.2s ease;
+ transition: background-color 0.2s ease,outline 0.2s ease,color 0.2s ease;
+ display: -webkit-inline-box;
+ display: -webkit-inline-flex;
+ display: -ms-inline-flexbox;
+ display: inline-flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -ms-flex-pack: center;
+ -webkit-justify-content: center;
+ justify-content: center;
+ cursor: pointer;
+ height: 2.25rem;
+ border-radius: 0.5rem;
+ padding-left: 0.625rem;
+ padding-right: 0.625rem;
+ --background: transparent;
+ --backgroundHover: rgb(232,235,255);
+ --color: rgb(75,86,187);
+ --colorHover: rgb(43,51,104);
+ --focus: rgba(93,108,208,0.2);
+}
+
+.emotion-3:hover,
+.emotion-3:focus,
+.emotion-3:active {
+ color: var(--colorHover);
+ background-color: var(--backgroundHover);
+}
+
+.emotion-3:focus,
+.emotion-3:active {
+ outline: 4px solid var(--focus);
+}
+
+.emotion-3:disabled,
+.emotion-3:disabled:hover {
+ color: rgb(166,173,194);
+ background-color: var(--background);
+ cursor: not-allowed;
+}
+
+<div>
+ <pre
+ class=" emotion-0 emotion-1"
+ >
+ <code
+ class="hljs sw-inline"
+ >
+ <span
+ class="hljs-string"
+ >
+ One
+ </span>
+
+ <span
+ class="hljs-string"
+ >
+ line
+ </span>
+
+ <span
+ class="hljs-string"
+ >
+ command
+ </span>
+ </code>
+ <button
+ aria-label="edit"
+ class="sw-ml-2 emotion-2 emotion-3 emotion-4"
+ type="button"
+ >
+ <svg
+ aria-hidden="true"
+ class=""
+ fill="currentColor"
+ focusable="false"
+ height="16"
+ role="img"
+ style="display: inline-block; user-select: none; vertical-align: middle; overflow: visible;"
+ viewBox="0 0 16 16"
+ width="16"
+ >
+ <path
+ d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"
+ />
+ </svg>
+ </button>
+ </pre>
+</div>
+`;
+
+exports[`should handle multiple lines of code 1`] = `
+.emotion-0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ overflow-x: auto;
+ padding: 1.5rem;
+}
+
+.emotion-0 code {
+ color: rgb(51,53,60);
+ background: rgb(252,252,253);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 400;
+}
+
+.emotion-0 code.hljs {
+ padding: unset;
+}
+
+.emotion-0 .hljs-variable,
+.emotion-0 .hljs-meta {
+ color: rgb(51,53,60);
+}
+
+.emotion-0 .hljs-doctag,
+.emotion-0 .hljs-title,
+.emotion-0 .hljs-title.class_,
+.emotion-0 .hljs-title.function_ {
+ color: rgb(34,84,192);
+}
+
+.emotion-0 .hljs-comment {
+ color: rgb(109,111,119);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-style: italic;
+}
+
+.emotion-0 .hljs-tag,
+.emotion-0 .hljs-type,
+.emotion-0 .hljs-keyword {
+ color: rgb(152,29,150);
+ font-family: Ubuntu Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 700;
+}
+
+.emotion-0 .hljs-literal,
+.emotion-0 .hljs-number {
+ color: rgb(126,83,5);
+}
+
+.emotion-0 .hljs-string {
+ color: rgb(32,105,31);
+}
+
+.emotion-0 .hljs-meta .hljs-keyword {
+ color: rgb(47,103,48);
+}
+
+.emotion-0.code-wrap {
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+.emotion-0 mark {
+ color: rgb(217,45,32);
+ background-color: rgb(197,205,223);
+ font-weight: 400;
+ border-radius: 0.25rem;
+ padding: 0.25rem;
+}
+
+.emotion-0.simple-one-line {
+ min-height: 1.25rem;
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+<div>
+ <pre
+ class=" emotion-0 emotion-1"
+ >
+ <code
+ class="hljs"
+ >
+ <span
+ class="hljs-attr"
+ >
+ foo:
+ </span>
+
+ <span
+ class="hljs-string"
+ >
+ bar
+ </span>
+
+
+ <span
+ class="hljs-attr"
+ >
+ pleh:
+ </span>
+
+ <span
+ class="hljs-string"
+ >
+ help
+ </span>
+
+
+ <span
+ class="hljs-attr"
+ >
+ stuff:
+ </span>
+
+
+ <span
+ class="hljs-attr"
+ >
+ foo:
+ </span>
+
+ <span
+ class="hljs-string"
+ >
+ bar
+ </span>
+
+
+ <span
+ class="hljs-attr"
+ >
+ bar:
+ </span>
+
+ <span
+ class="hljs-string"
+ >
+ foo
+ </span>
+ </code>
+ </pre>
+</div>
+`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { PencilIcon as PencilOcticonIcon } from '@primer/octicons-react';
+import { OcticonHoc } from './Icon';
+
+export const PencilIcon = OcticonHoc(PencilOcticonIcon);
export { OpenNewTabIcon } from './OpenNewTabIcon';
export { OverviewQGNotComputedIcon } from './OverviewQGNotComputedIcon';
export { OverviewQGPassedIcon } from './OverviewQGPassedIcon';
+export { PencilIcon } from './PencilIcon';
export { ProjectIcon } from './ProjectIcon';
export { PullRequestIcon } from './PullRequestIcon';
export { RefreshIcon } from './RefreshIcon';
export { Badge } from './Badge';
export { BarChart } from './BarChart';
export * from './Card';
+export * from './CodeSnippet';
export * from './CoverageIndicator';
export * from './DatePicker';
export * from './DateRangePicker';
darker: COLORS.red[800],
};
+const codeSnippetLight = {
+ annotations: [34, 84, 192],
+ body: [51, 53, 60],
+ constants: [126, 83, 5],
+ comments: [109, 111, 119],
+ keyword: [152, 29, 150],
+ string: [32, 105, 31],
+ 'keyword-light': [28, 28, 163], // Not used currently in code snippet
+ 'preprocessing-directive': [47, 103, 48],
+};
+
export const lightTheme = {
id: 'light-theme',
highlightTheme: 'atom-one-light.css',
codeSnippetBackground: COLORS.blueGrey[25],
codeSnippetBorder: COLORS.blueGrey[100],
codeSnippetHighlight: secondary.default,
+ codeSnippetBody: codeSnippetLight.body,
+ codeSnippetAnnotations: codeSnippetLight.annotations,
+ codeSnippetComments: codeSnippetLight.comments,
+ codeSnippetConstants: codeSnippetLight.constants,
+ codeSnippetKeyword: codeSnippetLight.keyword,
+ codeSnippetString: codeSnippetLight.string,
+ codeSnippetKeywordLight: codeSnippetLight['keyword-light'],
+ codeSnippetPreprocessingDirective: codeSnippetLight['preprocessing-directive'],
+ codeSnippetInline: COLORS.blueGrey[500],
// code viewer
codeLineIssueIndicator: COLORS.blueGrey[400], // Should be blueGrey[300], to be changed once code viewer is reworked
eslint-plugin-import: 2.27.5
eslint-plugin-local-rules: 1.3.2
eslint-plugin-typescript-sort-keys: 2.3.0
+ highlight.js: 11.7.0
history: 5.3.0
jest: 29.5.0
postcss: 8.4.21
languageName: node
linkType: hard
+"highlight.js@npm:11.7.0":
+ version: 11.7.0
+ resolution: "highlight.js@npm:11.7.0"
+ checksum: 19e3fb8b56f4b361b057a8523b989dfeb6479bbd1e29cec3fac6fa5c78d09927d5fa61b7dba6631fdb57cfdca9b3084aa4da49405ceaf4a67f67beae2ed5b77d
+ languageName: node
+ linkType: hard
+
"history@npm:5.3.0":
version: 5.3.0
resolution: "history@npm:5.3.0"