(chore)react-widget: add linter

This commit is contained in:
ManishMadan2882 committed 2026-03-26 02:06:49 +05:30
1 parent a3e6a5622d
commit c4968a641e
14 files changed
+4691 -1067

No files matched your search

+72
View File
@@ -0,0 +1,72 @@
import js from '@eslint/js'
import tsParser from '@typescript-eslint/parser'
import tsPlugin from '@typescript-eslint/eslint-plugin'
import react from 'eslint-plugin-react'
import unusedImports from 'eslint-plugin-unused-imports'
import prettier from 'eslint-plugin-prettier'
import globals from 'globals'
export default [
{
ignores: [
'node_modules/',
'dist/',
'prettier.config.cjs',
'custom.d.ts',
'package-lock.json',
'package.json',
],
},
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: tsParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.es2021,
...globals.node,
},
},
plugins: {
'@typescript-eslint': tsPlugin,
react,
'unused-imports': unusedImports,
prettier,
},
rules: {
...js.configs.recommended.rules,
...tsPlugin.configs.recommended.rules,
...react.configs.recommended.rules,
...prettier.configs.recommended.rules,
'react/prop-types': 'off',
'unused-imports/no-unused-imports': 'error',
'react/react-in-jsx-scope': 'off',
'no-undef': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'warn',
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
],
'@typescript-eslint/no-unused-expressions': 'warn',
'prettier/prettier': [
'error',
{
endOfLine: 'auto',
},
],
},
settings: {
react: {
version: 'detect',
},
},
},
]
+3317 -22
View File
File diff suppressed because it is too large. Load diff
+13 -1
View File
@@ -35,7 +35,9 @@
"serve": "parcel serve -p 3000",
"dev": "parcel -p 3000",
"test": "jest",
"lint": "eslint",
"lint": "eslint ./src --ext .jsx,.js,.ts,.tsx",
"lint-fix": "eslint ./src --ext .jsx,.js,.ts,.tsx --fix",
"format": "prettier ./src --write",
"check": "tsc --noEmit",
"ci": "yarn build && yarn test && yarn lint && yarn check"
},
@@ -60,14 +62,24 @@
"@babel/core": "^7.24.0",
"@babel/preset-env": "^7.24.0",
"@babel/preset-react": "^7.23.3",
"@eslint/js": "^9.39.4",
"@parcel/packager-ts": "^2.16.4",
"@parcel/transformer-typescript-types": "^2.16.4",
"@types/dompurify": "^3.0.5",
"@types/markdown-it": "^14.1.2",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^8.57.2",
"@typescript-eslint/parser": "^8.57.2",
"babel-loader": "^10.1.1",
"eslint": "^9.39.4",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-unused-imports": "^4.4.1",
"globals": "^15.15.0",
"parcel": "^2.16.4",
"prettier": "^3.8.1",
"process": "^0.11.10",
"svgo": "^3.3.3",
"typescript": "^5.3.3"
@@ -0,0 +1,8 @@
module.exports = {
trailingComma: 'all',
tabWidth: 2,
semi: true,
singleQuote: true,
printWidth: 80,
};
+7 -7
View File
@@ -1,11 +1,11 @@
import React from "react"
import {DocsGPTWidget} from "./components/DocsGPTWidget"
import {SearchBar} from "./components/SearchBar"
import React from 'react';
import { DocsGPTWidget } from './components/DocsGPTWidget';
import { SearchBar } from './components/SearchBar';
export const App = () => {
return (
<div>
<SearchBar/>
<DocsGPTWidget/>
<SearchBar />
<DocsGPTWidget />
</div>
)
}
);
};
+6 -4
View File
@@ -1,10 +1,10 @@
//exports browser ready methods
import { createRoot } from "react-dom/client";
import { createRoot } from 'react-dom/client';
import { DocsGPTWidget } from './components/DocsGPTWidget';
import { SearchBar } from './components/SearchBar';
import React from "react";
import React from 'react';
if (typeof window !== 'undefined') {
const renderWidget = (elementId: string, props = {}) => {
const root = createRoot(document.getElementById(elementId) as HTMLElement);
@@ -14,9 +14,11 @@ if (typeof window !== 'undefined') {
const root = createRoot(document.getElementById(elementId) as HTMLElement);
root.render(<SearchBar {...props} />);
};
(window as any).renderDocsGPTWidget = renderWidget;
(window as unknown as Record<string, unknown>).renderDocsGPTWidget =
renderWidget;
(window as any).renderSearchBar = renderSearchBar;
(window as unknown as Record<string, unknown>).renderSearchBar =
renderSearchBar;
}
export { DocsGPTWidget, SearchBar };
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -1,3 +1,3 @@
//exports methods for React
export {SearchBar} from "./components/SearchBar"
export { DocsGPTWidget } from "./components/DocsGPTWidget";
export { SearchBar } from './components/SearchBar';
export { DocsGPTWidget } from './components/DocsGPTWidget';
+5 -6
View File
@@ -1,8 +1,7 @@
//development
import { createRoot } from "react-dom/client";
import { App } from "./App";
import React from "react";
const container = document.getElementById("app") as HTMLElement;
const root = createRoot(container)
import { createRoot } from 'react-dom/client';
import { App } from './App';
import React from 'react';
const container = document.getElementById('app') as HTMLElement;
const root = createRoot(container);
root.render(<App />);
@@ -1,20 +1,24 @@
import { Result } from "@/types";
async function getSearchResults(question: string, apiKey: string, apiHost: string, signal: AbortSignal): Promise<Result[]> {
import { Result } from '@/types';
async function getSearchResults(
question: string,
apiKey: string,
apiHost: string,
signal: AbortSignal,
): Promise<Result[]> {
const payload = {
question,
api_key: apiKey
api_key: apiKey,
};
try {
const response = await fetch(`${apiHost}/api/search`, {
method: "POST",
method: 'POST',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
signal: signal
signal: signal,
});
if (!response.ok) {
@@ -23,15 +27,12 @@ async function getSearchResults(question: string, apiKey: string, apiHost: strin
const data: Result[] = await response.json();
return data;
} catch (error) {
if (!(error instanceof DOMException && error.name == "AbortError")) {
console.error("Failed to fetch documents:", error);
if (!(error instanceof DOMException && error.name == 'AbortError')) {
console.error('Failed to fetch documents:', error);
}
throw error;
}
}
export {
getSearchResults
}
export { getSearchResults };
@@ -1,5 +1,3 @@
import { FEEDBACK } from "@/types";
interface HistoryItem {
prompt: string;
response?: string;
@@ -30,7 +28,9 @@ export function fetchAnswerStreaming({
history = [],
conversationId = null,
apiHost = '',
onEvent = () => { console.log("Event triggered, but no handler provided."); }
onEvent = () => {
console.log('Event triggered, but no handler provided.');
},
}: FetchAnswerStreamingProps): Promise<void> {
return new Promise<void>((resolve, reject) => {
const body = {
@@ -38,7 +38,7 @@ export function fetchAnswerStreaming({
history: JSON.stringify(history),
conversation_id: conversationId,
model: 'default',
api_key: apiKey
api_key: apiKey,
};
fetch(apiHost + '/stream', {
method: 'POST',
@@ -52,7 +52,7 @@ export function fetchAnswerStreaming({
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let counter = 0;
let counter = 0; // eslint-disable-line @typescript-eslint/no-unused-vars
const processStream = ({
done,
value,
@@ -95,12 +95,14 @@ export function fetchAnswerStreaming({
});
}
export const sendFeedback = (payload: FeedbackPayload, apiHost: string): Promise<Response> => {
export const sendFeedback = (
payload: FeedbackPayload,
apiHost: string,
): Promise<Response> => {
return fetch(`${apiHost}/api/feedback`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
},
body: JSON.stringify({
question: payload.question,
@@ -108,7 +110,7 @@ export const sendFeedback = (payload: FeedbackPayload, apiHost: string): Promis
feedback: payload.feedback,
api_key: payload.apikey,
conversation_id: payload.conversation_id,
question_index: payload.question_index
question_index: payload.question_index,
}),
});
};
+26 -22
View File
@@ -38,7 +38,7 @@ export interface Query {
response?: string;
feedback?: FEEDBACK;
error?: string;
sources?: { title: string; text: string, source:string }[];
sources?: { title: string; text: string; source: string }[];
conversationId?: string | null;
title?: string | null;
}
@@ -51,30 +51,34 @@ export interface WidgetProps {
description?: string;
heroTitle?: string;
heroDescription?: string;
size?: 'small' | 'medium' | 'large' | {
custom: {
width: string;
height: string;
maxWidth?: string;
maxHeight?: string;
};
};
theme?:THEME,
buttonIcon?:string;
buttonText?:string;
buttonBg?:string;
collectFeedback?:boolean;
size?:
| 'small'
| 'medium'
| 'large'
| {
custom: {
width: string;
height: string;
maxWidth?: string;
maxHeight?: string;
};
};
theme?: THEME;
buttonIcon?: string;
buttonText?: string;
buttonBg?: string;
collectFeedback?: boolean;
showSources?: boolean;
defaultOpen?: boolean;
}
export interface WidgetCoreProps extends WidgetProps {
widgetRef?:React.RefObject<HTMLDivElement> | null;
handleClose?:React.MouseEventHandler | undefined;
isOpen:boolean;
export interface WidgetCoreProps extends WidgetProps {
widgetRef?: React.RefObject<HTMLDivElement> | null;
handleClose?: React.MouseEventHandler | undefined;
isOpen: boolean;
prefilledQuery?: string;
}
export interface SearchBarProps {
export interface SearchBarProps {
apiHost?: string;
apiKey?: string;
theme?: THEME;
@@ -84,7 +88,7 @@ export interface SearchBarProps {
}
export interface Result {
text:string;
title:string;
source:string;
text: string;
title: string;
source: string;
}
+29 -13
View File
@@ -30,11 +30,15 @@ interface ParsedElement {
tag: string;
}
export const processMarkdownString = (markdown: string, keyword?: string): ParsedElement[] => {
export const processMarkdownString = (
markdown: string,
keyword?: string,
): ParsedElement[] => {
const lines = markdown.trim().split('\n');
const keywordLower = keyword?.toLowerCase();
const escapeRegExp = (str: string) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
const escapeRegExp = (str: string) =>
str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
const escapedKeyword = keyword ? escapeRegExp(keyword) : '';
const keywordRegex = keyword ? new RegExp(`(${escapedKeyword})`, 'gi') : null;
@@ -56,7 +60,7 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
const codeContent = codeBlockContent.join('\n');
const parsedElement: ParsedElement = {
content: codeContent,
tag: 'code'
tag: 'code',
};
if (!firstLine) {
@@ -64,7 +68,10 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
}
if (keywordLower && codeContent.toLowerCase().includes(keywordLower)) {
parsedElement.content = parsedElement.content.replace(keywordRegex!, '<span class="highlight">$1</span>');
parsedElement.content = parsedElement.content.replace(
keywordRegex!,
'<span class="highlight">$1</span>',
);
matchingLines.push(parsedElement);
}
}
@@ -89,30 +96,30 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
content = headingMatch[2];
parsedElement = {
content: content,
tag: 'heading'
tag: 'heading',
};
} else if (bulletMatch) {
content = bulletMatch[1];
parsedElement = {
content: content,
tag: 'bulletList'
tag: 'bulletList',
};
} else if (numberedMatch) {
content = numberedMatch[1];
parsedElement = {
content: content,
tag: 'numberedList'
tag: 'numberedList',
};
} else if (blockquoteMatch) {
content = blockquoteMatch[1];
parsedElement = {
content: content,
tag: 'blockquote'
tag: 'blockquote',
};
} else {
parsedElement = {
content: content,
tag: 'text'
tag: 'text',
};
}
@@ -120,8 +127,14 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
firstLine = parsedElement;
}
if (keywordLower && parsedElement.content.toLowerCase().includes(keywordLower)) {
parsedElement.content = parsedElement.content.replace(keywordRegex!, '<span class="highlight">$1</span>');
if (
keywordLower &&
parsedElement.content.toLowerCase().includes(keywordLower)
) {
parsedElement.content = parsedElement.content.replace(
keywordRegex!,
'<span class="highlight">$1</span>',
);
matchingLines.push(parsedElement);
}
}
@@ -130,7 +143,7 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
const codeContent = codeBlockContent.join('\n');
const parsedElement: ParsedElement = {
content: codeContent,
tag: 'code'
tag: 'code',
};
if (!firstLine) {
@@ -138,7 +151,10 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
}
if (keywordLower && codeContent.toLowerCase().includes(keywordLower)) {
parsedElement.content = parsedElement.content.replace(keywordRegex!, '<span class="highlight">$1</span>');
parsedElement.content = parsedElement.content.replace(
keywordRegex!,
'<span class="highlight">$1</span>',
);
matchingLines.push(parsedElement);
}
}