lodash#escapeRegExp TypeScript Examples
The following examples show how to use
lodash#escapeRegExp.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: order.ts From Adachi-BOT with MIT License | 6 votes |
constructor( config: OrderConfig, botCfg: BotConfig ) {
super( config );
const globalHeader: string = botCfg.header;
const headers: string[] = config.headers.map( el => Order.header( el, globalHeader ) );
let rawRegs = <string[][]>config.regexps;
const isDeep: boolean = config.regexps.some( el => el instanceof Array );
if ( !isDeep ) {
rawRegs = [ <string[]>config.regexps ];
}
for ( let header of headers ) {
const pair: RegPair = { header, genRegExps: [] };
for ( let reg of rawRegs ) {
const r: string = [ "", ...reg ].join( " *" );
const h: string = escapeRegExp( header );
const pattern: string = Order.addStartStopChar(
h + r,
config.start !== false,
config.stop !== false
);
pair.genRegExps.push( Order.regexp( pattern, this.ignoreCase ) );
}
this.regPairs.push( pair );
}
}
Example #2
Source File: GetTypeDeclarationsOfFn.ts From next-basics with GNU General Public License v3.0 | 6 votes |
export function GetTypeDeclarationsOfFn(
name: string,
functions: StoryboardFunction[]
): ExtraLib[] {
const libs: ExtraLib[] = [];
const exports: string[] = [];
for (const fn of functions) {
if (fn.name === name) {
continue;
}
libs.push({
filePath: `storyboard/functions/${fn.name}.${
fn.typescript ? "ts" : "js"
}`,
content: fn.source.replace(
new RegExp(`\\bfunction\\s+${escapeRegExp(fn.name)}\\b\\s*\\(`),
"export $&"
),
model: true,
});
exports.push(`export * from "./functions/${fn.name}";`);
}
libs.push(
{
filePath: "storyboard/FN-exports.ts",
content: exports.join("\n"),
},
{
filePath: "storyboard/FN.d.ts",
content: 'declare const FN: typeof import("./FN-exports");',
}
);
return libs;
}
Example #3
Source File: generateDoc.ts From next-core with GNU General Public License v3.0 | 6 votes |
matchEventDecorate = (eventType: string, fileText: string) => {
const reg = new RegExp(
"(?<=(\\/\\*\\*(.|@|\\s)*?\\*\\/\\s*))" +
"@event\\(.*?(type:\\s*(\"|')" +
escapeRegExp(eventType) +
"(\"|')).*?\\)"
);
return fileText.match(reg);
}
Example #4
Source File: SearchResultItem.tsx From querybook with Apache License 2.0 | 6 votes |
HighlightTitle: React.FunctionComponent<{
title: string;
searchString: string;
}> = ({ title, searchString }) => {
const highlightReplace = (text: string) => `<mark>${text}</mark>`;
let highlightedTitle = title;
if (searchString && searchString.length) {
const searchStringRegex = new RegExp(escapeRegExp(searchString), 'ig');
highlightedTitle = title.replace(searchStringRegex, highlightReplace);
}
return highlightedTitle && highlightedTitle !== 'Untitled' ? (
<AccentText size="smedium" weight="bold" color="text" hover>
<div
className="result-item-title"
dangerouslySetInnerHTML={{
__html: highlightedTitle,
}}
/>
</AccentText>
) : (
<UntitledText size="smedium" />
);
}
Example #5
Source File: logs.ts From grafana-chinese with Apache License 2.0 | 6 votes |
LogsParsers: { [name: string]: LogsParser } = {
JSON: {
buildMatcher: label => new RegExp(`(?:{|,)\\s*"${label}"\\s*:\\s*"?([\\d\\.]+|[^"]*)"?`),
getFields: line => {
try {
const parsed = JSON.parse(line);
return Object.keys(parsed).map(key => {
return `"${key}":${JSON.stringify(parsed[key])}`;
});
} catch {}
return [];
},
getLabelFromField: field => (field.match(/^"([^"]+)"\s*:/) || [])[1],
getValueFromField: field => (field.match(/:\s*(.*)$/) || [])[1],
test: line => {
try {
return JSON.parse(line);
} catch (error) {}
},
},
logfmt: {
buildMatcher: label => new RegExp(`(?:^|\\s)${escapeRegExp(label)}=("[^"]*"|\\S+)`),
getFields: line => {
const fields: string[] = [];
line.replace(new RegExp(LOGFMT_REGEXP, 'g'), substring => {
fields.push(substring.trim());
return '';
});
return fields;
},
getLabelFromField: field => (field.match(LOGFMT_REGEXP) || [])[1],
getValueFromField: field => (field.match(LOGFMT_REGEXP) || [])[2],
test: line => LOGFMT_REGEXP.test(line),
},
}
Example #6
Source File: switch.ts From Adachi-BOT with MIT License | 5 votes |
constructor( config: SwitchConfig, botCfg: BotConfig ) {
super( config );
if ( config.onKey === config.offKey ) {
throw `指令 ${ config.cmdKey } 配置错误: onKey 与 offKey 不可相同`;
}
if ( config.offKey.length === 0 || config.onKey.length === 0 ) {
throw `指令 ${ config.cmdKey } 配置错误: onKey 和 offKey 不可为空`;
}
const globalHeader: string = botCfg.header;
const process: ( h: string ) => string = h => escapeRegExp(
Switch.header( h, globalHeader )
);
const addChar: ( s: string ) => string = s => Switch.addStartStopChar(
s, config.start !== false, config.stop !== false
);
this.mode = config.mode;
this.header = "";
if ( config.mode === "single" ) {
let reg: string = config.regexp instanceof Array
? [ "", ...config.regexp ].join( " *" )
: config.regexp;
const h: string = process( config.header );
const r: string = reg.replace(
"#{OPT}",
`(${ config.onKey }|${ config.offKey })`
);
this.regexps.push( Switch.regexp( addChar( h + r ), this.ignoreCase ) );
this.keys = [ config.onKey, config.offKey ];
this.header = h;
} else {
const r: string = config.regexp instanceof Array
? [ "", ...config.regexp.filter( el => el !== "#{OPT}" ) ].join( " *" )
: config.regexp.replace( "#{OPT}", "" ).trim();
const h1: string = process( config.onKey );
const h2: string = process( config.offKey );
this.regexps.push( Switch.regexp(
addChar( `(${ h1 }|${ h2 })${ r }` ),
this.ignoreCase
) );
this.keys = [ h1, h2 ];
}
}
Example #7
Source File: GetUnusedImages.ts From next-basics with GNU General Public License v3.0 | 5 votes |
export async function DeleteUnusedImages({
appId,
projectId,
storyboard,
bucketName,
}: DeleteUnUseImagesProps): Promise<{ unusedImages: Array<imageItem> }> {
// 获取所有图片
const allImageReq = InstanceApi_postSearch("MICRO_APP_RESOURCE_IMAGE", {
fields: { url: true },
page_size: 3000,
query: { "project.instanceId": projectId },
});
const allDocListReq = DocumentApi_getDocumentsTreeByAppId(appId);
const [allImageResponse, allDocResponse] = await Promise.all([
allImageReq,
allDocListReq,
]);
if (allImageResponse.list.length === 0) {
return {
unusedImages: [],
};
}
const regexString = `${escapeRegExp(
`/next/api/gateway/object_store.object_store.GetObject/api/v1/objectStore/bucket/${bucketName}/object/`
)}(.+?\\.(?:png|jpe?g|gif))`;
const regexSingleMatch = new RegExp(regexString);
const regexMultipleMatch = new RegExp(regexSingleMatch, "g");
const allImagesMap = new Map<string, string>();
allImageResponse.list.forEach((item) => {
const matches = item.url.match(regexSingleMatch);
if (!matches) {
throw new Error(`Unexpected image url: ${item.url}`);
}
allImagesMap.set(matches[1], item.instanceId);
});
const getDocDetailReq = allDocResponse.documentsTree.map((item) =>
DocumentApi_getDocumentsDetails(item.documentId)
);
const allDocContentList = (await Promise.all(getDocDetailReq)).map(
(item) => item.content
);
const usedImages = new Set<string>();
findUsedImagesInStoryboard(storyboard, regexMultipleMatch, usedImages);
findUsedImagesInString(
allDocContentList.join("\n"),
regexMultipleMatch,
usedImages
);
const unusedImages: Array<imageItem> = [];
for (const [imageName, instanceId] of allImagesMap.entries()) {
if (!usedImages.has(imageName)) {
unusedImages.push({
name: imageName,
instanceId,
});
}
}
return {
unusedImages,
};
}
Example #8
Source File: generateDoc.ts From next-core with GNU General Public License v3.0 | 5 votes |
propertyDefinitionReg = (propertyName: string) => {
return new RegExp(
"\\|\\s*[\"']?" +
escapeRegExp(propertyName) +
"((\\s*[\"']?(?<!\\\\)\\|(((?<=\\\\)\\|)|[^|])*){4}\\|)"
);
}
Example #9
Source File: generateDoc.ts From next-core with GNU General Public License v3.0 | 5 votes |
commentReg = (text: string) => {
return new RegExp(
"(?<=(\\/\\*\\*(.|@|\\s)*?\\*\\/\\s*))" + escapeRegExp(text)
);
}
Example #10
Source File: generateDoc.ts From next-core with GNU General Public License v3.0 | 5 votes |
matchMethodDecorate = (methodName: string, fileText: string) => {
const reg = new RegExp(
"(?<=(\\/\\*\\*(.|@|\\s)*?\\*\\/\\s*))" +
"@method\\([^)]*?\\)\\s*" +
escapeRegExp(methodName)
);
return fileText.match(reg);
}
Example #11
Source File: lexical.ts From next-core with GNU General Public License v3.0 | 5 votes |
export function getRegExpOfPlaceholder(symbols: string | string[]): RegExp {
return new RegExp(
`(${([] as string[])
.concat(symbols)
.map((symbol) => escapeRegExp(symbol))
.join("|")})\\{`
);
}
Example #12
Source File: InputTypeahead.tsx From hub with Apache License 2.0 | 4 votes |
InputTypeahead = forwardRef((props: Props, ref: Ref<RefInputTypeaheadField>) => {
const inputEl = useRef<HTMLInputElement>(null);
const itemsWrapper = useRef<HTMLDivElement | null>(null);
const [inputValue, setInputValue] = useState('');
const [highlightedText, setHighlightedText] = useState<RegExp | null>(null);
const [highlightedItem, setHighlightedItem] = useState<number | null>(null);
useImperativeHandle(ref, () => ({
reset: () => {
setInputValue('');
},
getValue(): string {
return inputValue;
},
updateValue(newValue: string): void {
setInputValue(newValue);
},
}));
const getVisibleItems = useCallback((): Option[] | null => {
let filteredItems: Option[] = [];
let elements: any[] | null = null;
if (!isNull(highlightedItem)) {
setHighlightedItem(null);
}
if (isUndefined(props.displayItemsInValueLength) || inputValue.length >= props.displayItemsInValueLength) {
filteredItems = props.options.filter((opt: Option) => opt.name.toLowerCase().includes(inputValue.toLowerCase()));
elements = orderBy(
filteredItems,
[
(item: Option) =>
props.selected.hasOwnProperty(item.filterKey) && props.selected[item.filterKey].includes(item.id.toString())
? -1
: 1,
'total',
],
['asc', 'desc']
);
// Scroll top when new visible items are displayed
if (itemsWrapper && itemsWrapper.current) {
itemsWrapper.current.scroll(0, 0);
}
}
return elements;
}, [highlightedItem, props.displayItemsInValueLength, props.options, props.selected, inputValue]);
const getSelectedItems = useCallback((): Option[] => {
let selectedItems: Option[] = [];
Object.keys(props.selected).forEach((fKey: string) => {
props.selected[fKey].forEach((item: string) => {
const selected = props.options.find((opt: Option) => opt.id.toString() === item && opt.filterKey === fKey);
if (!isUndefined(selected)) {
selectedItems.push(selected);
}
});
});
return orderBy(selectedItems, 'total', 'desc');
}, [props.options, props.selected]);
const getOptionName = (name: string): JSX.Element => {
if (!isNull(highlightedText)) {
const stringParts: string[] = compact(name.split(highlightedText));
if (stringParts.length === 1) {
return (
<span
className={classnames({
'fw-bold highlighted': name.toLowerCase() === inputValue.toLowerCase(),
})}
>
{name}
</span>
);
}
return (
<>
{stringParts.map((str: string, index: number) => (
<span
key={`${name}_${index}`}
className={classnames({
'fw-bold highlighted': str.toLowerCase() === inputValue.toLowerCase(),
})}
>
{str}
</span>
))}
</>
);
} else {
return <>{name}</>;
}
};
const [visibleItems, setVisibleItems] = useState<Option[] | null>(null);
const [selectedItems, setSelectedItems] = useState<Option[]>(getSelectedItems());
useEffect(() => {
setVisibleItems(getVisibleItems());
}, [inputValue, props.options]); /* eslint-disable-line react-hooks/exhaustive-deps */
useEffect(() => {
setSelectedItems(getSelectedItems());
}, [getSelectedItems, props.selected]);
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
e.preventDefault();
setHighlightedItem(null);
setInputValue(e.target.value);
const escapedValue = escapeRegExp(e.target.value.toLowerCase());
setHighlightedText(e.target.value !== '' ? new RegExp(`(${escapedValue})`, 'gi') : null);
};
const onSelect = (filterKey: string, id: string, isSelected: boolean) => {
setHighlightedItem(null);
props.onChange(filterKey, id, !isSelected);
if (props.onChangeSelection) {
props.onChangeSelection();
}
};
const onKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
switch (e.key) {
case 'ArrowDown':
updateHighlightedItem('down');
return;
case 'ArrowUp':
updateHighlightedItem('up');
return;
case 'Enter':
if (!isNull(highlightedItem) && visibleItems) {
const item = visibleItems[highlightedItem];
const isSelected =
props.selected.hasOwnProperty(item.filterKey) &&
props.selected[item.filterKey].includes(item.id.toString());
onSelect(item.filterKey, item.id.toString(), isSelected);
}
return;
default:
return;
}
};
const scrollDropdown = (index: number) => {
if (itemsWrapper && itemsWrapper.current) {
const itemsOnScreen = Math.floor(itemsWrapper.current.clientHeight / ITEM_HEIGHT);
if (index + 1 > itemsOnScreen) {
itemsWrapper.current.scroll(0, (index + 1 - itemsOnScreen) * ITEM_HEIGHT);
} else {
itemsWrapper.current.scroll(0, 0);
}
}
};
const updateHighlightedItem = (arrow: 'up' | 'down') => {
if (!isNull(highlightedItem)) {
let newIndex: number = arrow === 'up' ? highlightedItem - 1 : highlightedItem + 1;
if (newIndex > visibleItems!.length - 1) {
newIndex = 0;
}
if (newIndex < 0) {
newIndex = visibleItems!.length - 1;
}
scrollDropdown(newIndex);
setHighlightedItem(newIndex);
} else {
if (visibleItems && visibleItems.length > 0) {
const newIndex = arrow === 'up' ? visibleItems.length - 1 : 0;
scrollDropdown(newIndex);
setHighlightedItem(newIndex);
}
}
};
if (props.options.length === 0) return null;
return (
<>
<div className={`mb-3 input-group-sm ${styles.inputWrapper} ${props.inputWrapperClassName}`}>
<input
ref={inputEl}
type="text"
placeholder={props.placeholder || `Search ${props.label}`}
className={classnames(
'flex-grow-1 form-control',
styles.input,
{ 'ps-3 pe-4': props.searchIcon },
{ 'px-3': isUndefined(props.searchIcon) || !props.searchIcon }
)}
name={`inputTypeahead_${props.label}`}
value={inputValue}
onChange={onChange}
onKeyDown={onKeyDown}
spellCheck="false"
autoFocus={!isUndefined(props.autofocus) && props.autofocus}
/>
{props.searchIcon && <FaSearch className={`text-muted position-absolute ${styles.searchIcon}`} />}
{!isUndefined(props.additionalInfo) && <div className="alert p-0 mt-3">{props.additionalInfo}</div>}
</div>
{selectedItems.length > 0 && props.visibleClear && (
<div className="py-1 border-bottom">
<button
className="btn btn-sm w-100"
onClick={() => {
if (props.onClear) {
props.onClear();
}
}}
aria-label="Clear all"
>
<div className="d-flex flex-row align-items-center text-muted">
<IoIosClose />
<small className="ms-2">Clear all</small>
</div>
</button>
</div>
)}
{visibleItems && (
<>
{visibleItems.length === 0 ? (
<div className={`p-3 text-center ${props.listClassName}`}>
<small className="text-muted">Sorry, no matches found</small>
</div>
) : (
<div className={`${styles.itemsList} ${props.listClassName}`} ref={itemsWrapper}>
{visibleItems.map((opt: Option, index: number) => {
const isSelected =
props.selected.hasOwnProperty(opt.filterKey) &&
props.selected[opt.filterKey].includes(opt.id.toString());
const name = getOptionName(opt.name);
return (
<button
key={`opt_${opt.filterKey}_${opt.id}`}
data-testid="typeaheadDropdownBtn"
className={classnames(
'dropdown-item',
styles.option,
props.optClassName,
{
[styles.selected]: isSelected,
},
{
[styles.highlighted]: index === highlightedItem,
}
)}
onClick={() => {
onSelect(opt.filterKey, opt.id.toString(), isSelected);
if (props.onChangeSelection) {
props.onChangeSelection();
}
}}
aria-label={`${isSelected ? 'Unselect' : 'Select'} option`}
>
<div className="d-flex flex-row align-items-center position-relative">
{isSelected && (
<div className={`position-absolute ${styles.checkMark}`}>
<IoIosCheckmark />
</div>
)}
<InputTypeaheadOptionItem opt={opt} name={name} iconClassName={styles.icon} />
{isSelected && (
<div className={`position-absolute ${styles.close}`}>
<IoIosClose />
</div>
)}
</div>
</button>
);
})}
</div>
)}
</>
)}
</>
);
})
Example #13
Source File: SearchRepositories.tsx From hub with Apache License 2.0 | 4 votes |
SearchRepositories = (props: Props) => {
const inputEl = useRef<HTMLInputElement>(null);
const dropdownRef = useRef(null);
const itemsWrapper = useRef<HTMLDivElement | null>(null);
const [isSearching, setIsSearching] = useState(false);
const [repositories, setRepositories] = useState<Repository[] | null>(null);
const [searchName, setSearchName] = useState<string>('');
const [dropdownTimeout, setDropdownTimeout] = useState<NodeJS.Timeout | null>(null);
const [highlightedItem, setHighlightedItem] = useState<number | null>(null);
useOutsideClick([dropdownRef], !isNull(repositories), () => cleanSearch());
async function searchRepositories() {
try {
setIsSearching(true);
let query: SearchQuery = {
name: searchName,
limit: DEFAULT_LIMIT,
offset: 0,
};
if (props.extraQueryParams) {
query = { ...query, filters: props.extraQueryParams };
}
const data = await API.searchRepositories(query);
setRepositories(data.items);
setIsSearching(false);
} catch (err: any) {
if (err.kind !== ErrorKind.Unauthorized) {
alertDispatcher.postAlert({
type: 'danger',
message: 'An error occurred searching repositories, please try again later.',
});
} else {
props.onAuthError();
}
setRepositories(null);
setIsSearching(false);
}
}
const saveSelectedRepository = (item: Repository): void => {
setRepositories(null);
setSearchName('');
inputEl.current!.value = '';
props.onSelection(item);
setHighlightedItem(null);
};
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
setSearchName(e.target.value);
setHighlightedItem(null);
};
const checkIfRepoIsDisabled = (item: Repository): boolean => {
let isDisabled = false;
if (!isUndefined(props.disabledRepositories)) {
isDisabled =
(!isUndefined(props.disabledRepositories.ids) && props.disabledRepositories.ids.includes(item.repositoryId!)) ||
(!isUndefined(props.disabledRepositories.users) &&
!isNull(item.userAlias) &&
!isUndefined(item.userAlias) &&
props.disabledRepositories.users.includes(item.userAlias)) ||
(!isUndefined(props.disabledRepositories.organizations) &&
!isNull(item.organizationName) &&
!isUndefined(item.organizationName) &&
props.disabledRepositories.organizations.includes(item.organizationName));
}
return isDisabled;
};
const onKeyDown = (e: KeyboardEvent<HTMLInputElement>): void => {
switch (e.key) {
case 'Escape':
cleanSearch();
return;
case 'ArrowDown':
updateHighlightedItem('down');
return;
case 'ArrowUp':
updateHighlightedItem('up');
return;
case 'Enter':
e.preventDefault();
if (!isNull(repositories) && !isNull(highlightedItem)) {
const selectedRepo = repositories[highlightedItem];
if (selectedRepo && !checkIfRepoIsDisabled(selectedRepo)) {
saveSelectedRepository(selectedRepo);
}
}
return;
default:
return;
}
};
const updateHighlightedItem = (arrow: 'up' | 'down') => {
if (!isNull(repositories) && repositories.length > 0) {
if (!isNull(highlightedItem)) {
let newIndex: number = arrow === 'up' ? highlightedItem - 1 : highlightedItem + 1;
if (newIndex > repositories.length - 1) {
newIndex = 0;
}
if (newIndex < 0) {
newIndex = repositories.length - 1;
}
scrollDropdown(newIndex);
setHighlightedItem(newIndex);
} else {
const newIndex = arrow === 'up' ? repositories.length - 1 : 0;
scrollDropdown(newIndex);
setHighlightedItem(newIndex);
}
}
};
const forceFocus = (): void => {
if (!isNull(inputEl) && !isNull(inputEl.current)) {
inputEl.current.focus();
}
};
const cleanTimeout = () => {
if (!isNull(dropdownTimeout)) {
clearTimeout(dropdownTimeout);
setDropdownTimeout(null);
}
};
const cleanSearch = () => {
setRepositories(null);
setSearchName('');
setHighlightedItem(null);
};
const scrollDropdown = (index: number) => {
if (itemsWrapper && itemsWrapper.current) {
const itemsOnScreen = Math.floor(itemsWrapper.current.clientHeight / ITEM_HEIGHT) - 1;
if (index + 1 > itemsOnScreen) {
itemsWrapper.current.scroll(0, (index - itemsOnScreen) * ITEM_HEIGHT);
} else {
itemsWrapper.current.scroll(0, 0);
}
}
};
useEffect(() => {
const isInputFocused = inputEl.current === document.activeElement;
if (searchName.length >= MIN_CHARACTERS_SEARCH && isInputFocused) {
cleanTimeout();
setDropdownTimeout(
setTimeout(() => {
searchRepositories();
}, SEARCH_DELAY)
);
} else {
cleanSearch();
}
return () => {
if (!isNull(dropdownTimeout)) {
clearTimeout(dropdownTimeout);
}
};
}, [searchName]); /* eslint-disable-line react-hooks/exhaustive-deps */
return (
<div className="position-relative">
<div className="d-flex flex-row">
<div
className={`flex-grow-1 d-flex align-items-stretch overflow-hidden position-relative searchBar lh-base bg-white ${styles.inputWrapper}`}
>
<div
data-testid="searchBarIcon"
className={`d-flex align-items-center ${styles.iconWrapper}`}
onClick={forceFocus}
>
<FiSearch />
</div>
<input
ref={inputEl}
type="text"
className={`flex-grow-1 pe-4 ps-2 ps-md-0 border-0 shadow-none bg-transparent ${styles.input}`}
name="searchRepositoriesInput"
aria-label="Search repositories"
autoComplete="new-input"
onChange={onChange}
onKeyDown={onKeyDown}
spellCheck="false"
/>
{isSearching && (
<div className={`position-absolute text-secondary ${styles.loading}`}>
<span data-testid="searchBarSpinning" className="spinner-border spinner-border-sm" />
</div>
)}
</div>
</div>
{!isNull(repositories) && (
<div ref={dropdownRef} className={`dropdown-menu w-100 p-0 shadow-sm show overflow-hidden ${styles.dropdown}`}>
{repositories.length === 0 ? (
<p className="m-3 text-center">
We can't seem to find any repositories that match your search for{' '}
<span className="fw-bold">{searchName}</span>
</p>
) : (
<div className={`overflow-scroll ${styles.tableWrapper}`} ref={itemsWrapper}>
<table
className={`table table-hover table-sm mb-0 text-break ${styles.table}`}
role="grid"
aria-labelledby={props.label}
>
<thead>
<tr>
<th scope="col" className={`${styles.fitCell} d-none d-sm-table-cell`}></th>
<th scope="col" className={styles.repoCell}>
Repository
</th>
{props.visibleUrl && (
<th scope="col" className="d-none d-md-table-cell">
Url
</th>
)}
<th scope="col">Publisher</th>
</tr>
</thead>
<tbody>
{repositories.map((item: Repository, index: number) => {
const isDisabled = checkIfRepoIsDisabled(item);
return (
<tr
data-testid="repoItem"
role="button"
className={classnames(
{ [styles.clickableCell]: !isDisabled },
{ [styles.disabledCell]: isDisabled },
{ [styles.activeCell]: index === highlightedItem }
)}
onClick={() => {
if (!isDisabled) {
saveSelectedRepository(item);
}
}}
key={`repo_${item.name!}`}
onMouseOver={() => setHighlightedItem(index)}
onMouseOut={() => setHighlightedItem(null)}
>
<td className="align-middle text-center d-none d-sm-table-cell">
<div className="mx-2">
<RepositoryIcon kind={item.kind} className={`w-auto ${styles.icon}`} />
</div>
</td>
<td className="align-middle">
<div className={styles.truncateWrapper}>
<div className="text-truncate">
{searchName === '' ? (
<>{item.name}</>
) : (
<>
{regexifyString({
pattern: new RegExp(escapeRegExp(searchName), 'gi'),
decorator: (match: string, index: number) => {
return (
<span key={`match_${item.name}_${index}`} className="fw-bold highlighted">
{match}
</span>
);
},
input: item.name,
})}
</>
)}
</div>
</div>
</td>
{props.visibleUrl && (
<td className="align-middle d-none d-md-table-cell">
<div className={styles.truncateWrapper}>
<div className="text-truncate">
<small>{item.url}</small>
</div>
</div>
</td>
)}
<td className="align-middle">
<div className="text-dark d-flex flex-row align-items-center">
<span className={`me-1 ${styles.tinyIcon}`}>
{item.userAlias ? <FaUser /> : <MdBusiness />}
</span>
{item.userAlias || item.organizationDisplayName || item.organizationName}
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
)}
</div>
)}
</div>
);
}
Example #14
Source File: context.tsx From remix-project with MIT License | 4 votes |
SearchProvider = ({
children = [],
reducer = SearchReducer,
initialState = SearchingInitialState,
plugin = undefined
} = {}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const [files, setFiles] = useState([])
const clearSearchingTimeout = useRef(null)
const value = {
state,
setFind: (value: string) => {
plugin.cancel('fileManager')
dispatch({
type: 'SET_FIND',
payload: value
})
},
setReplace: (value: string) => {
dispatch({
type: 'SET_REPLACE',
payload: value
})
},
setReplaceEnabled: (value: boolean) => {
dispatch({
type: 'SET_REPLACE_ENABLED',
payload: value
})
},
setInclude: (value: string) => {
dispatch({
type: 'SET_INCLUDE',
payload: value
})
},
setExclude(value: string) {
dispatch({
type: 'SET_EXCLUDE',
payload: value
})
},
setCaseSensitive(value: boolean) {
dispatch({
type: 'SET_CASE_SENSITIVE',
payload: value
})
},
setWholeWord(value: boolean) {
dispatch({
type: 'SET_WHOLE_WORD',
payload: value
})
},
setRegex(value: boolean) {
dispatch({
type: 'SET_REGEX',
payload: value
})
},
setSearchResults(value: SearchResult[]) {
dispatch({
type: 'SET_SEARCH_RESULTS',
payload: value
})
},
reloadFile: async (file: string) => {
dispatch({
type: 'RELOAD_FILE',
payload: file
})
},
toggleUseRegex: () => {
dispatch({
type: 'TOGGLE_USE_REGEX',
payload: undefined
})
},
toggleCaseSensitive: () => {
dispatch({
type: 'TOGGLE_CASE_SENSITIVE',
payload: undefined
})
},
toggleMatchWholeWord: () => {
dispatch({
type: 'TOGGLE_MATCH_WHOLE_WORD',
payload: undefined
})
},
setReplaceWithoutConfirmation: (value: boolean) => {
dispatch({
type: 'SET_REPLACE_WITHOUT_CONFIRMATION',
payload: value
})
},
disableForceReload: (file: string) => {
dispatch({
type: 'DISABLE_FORCE_RELOAD',
payload: file
})
},
setCurrentFile: (file: string) => {
dispatch({
type: 'SET_CURRENT_FILE',
payload: file
})
},
setCurrentWorkspace: (workspace: any) => {
dispatch({
type: 'SET_CURRENT_WORKSPACE',
payload: workspace
})
},
updateCount: (count: number, file: string) => {
dispatch({
type: 'UPDATE_COUNT',
payload: { count, file }
})
},
setSearching(file: string) {
dispatch({
type: 'SET_SEARCHING',
payload: file
})
},
startSearch: () => {
dispatch({
type: 'START_SEARCH',
payload: undefined
})
},
setRun(value: boolean) {
dispatch({
type: 'SET_RUN',
payload: value
})
},
findText: async (path: string) => {
if (!plugin) return
try {
if (state.find.length < 1) return
value.setSearching(path)
const text = await plugin.call('fileManager', 'readFile', path)
const result: SearchResultLine[] = findLinesInStringWithMatch(
text,
createRegExFromFind()
)
clearTimeout(clearSearchingTimeout.current)
clearSearchingTimeout.current = setTimeout(() => value.setSearching(null), 500)
return result
} catch (e) {
console.log(e)
value.setSearching(null)
// do nothing
}
},
hightLightInPath: async (
result: SearchResult,
line: SearchResultLineLine
) => {
await plugin.call('editor', 'discardHighlight')
await plugin.call('editor', 'highlight', line.position, result.path)
await plugin.call(
'editor',
'revealRange',
line.position.start.line,
line.position.start.column,
line.position.end.line,
line.position.end.column
)
},
replaceText: async (result: SearchResult, line: SearchResultLineLine) => {
try {
await plugin.call('editor', 'discardHighlight')
await plugin.call('editor', 'highlight', line.position, result.path)
const content = await plugin.call(
'fileManager',
'readFile',
result.path
)
const replaced = replaceTextInLine(content, line, state.replace)
await plugin.call('fileManager', 'setFile', result.path, replaced)
setUndoState(content, replaced, result.path)
} catch (e) {
throw new Error(e)
}
},
replaceAllInFile: async (result: SearchResult) => {
await plugin.call('editor', 'discardHighlight')
const content = await plugin.call('fileManager', 'readFile', result.path)
const replaced = replaceAllInFile(
content,
createRegExFromFind(),
state.replace
)
await plugin.call('fileManager', 'setFile', result.path, replaced)
await plugin.call('fileManager', 'open', result.path)
setUndoState(content, replaced, result.path)
},
setUndoEnabled: (path: string, workspace: string, content: string) => {
dispatch({
type: 'SET_UNDO_ENABLED',
payload: {
path,
workspace,
content
}
})
},
undoReplace: async (buffer: undoBufferRecord) => {
const content = await plugin.call('fileManager', 'readFile', buffer.path)
if (buffer.newContent !== content) {
throw new Error('Can not undo replace, file has been changed.')
}
await plugin.call(
'fileManager',
'setFile',
buffer.path,
buffer.oldContent
)
await plugin.call('fileManager', 'open', buffer.path)
},
clearUndo: () => {
dispatch({
type: 'CLEAR_UNDO',
payload: undefined
})
},
clearStats: () => {
plugin.call('editor', 'discardHighlight')
dispatch({
type: 'CLEAR_STATS',
payload: undefined
})
},
cancelSearch: async (clearResults = true) => {
plugin.cancel('fileManager')
if (clearResults) value.clearStats()
value.setRun(false)
},
setClipped: (value: boolean) => {
dispatch({
type: 'SET_CLIPPED',
payload: value
})
}
}
const reloadStateForFile = async (file: string) => {
await value.reloadFile(file)
}
useEffect(() => {
plugin.on('filePanel', 'setWorkspace', async workspace => {
value.setSearchResults(null)
value.clearUndo()
value.setCurrentWorkspace(workspace.name)
setFiles(await getDirectory('/', plugin))
})
plugin.on('fileManager', 'fileSaved', async file => {
await reloadStateForFile(file)
await checkUndoState(file)
})
plugin.on('fileManager', 'rootFolderChanged', async file => {
const workspace = await plugin.call('filePanel', 'getCurrentWorkspace')
if (workspace) value.setCurrentWorkspace(workspace.name)
setFiles(await getDirectory('/', plugin))
})
plugin.on('fileManager', 'fileAdded', async file => {
setFiles(await getDirectory('/', plugin))
await reloadStateForFile(file)
})
plugin.on('fileManager', 'currentFileChanged', async file => {
value.setCurrentFile(file)
await checkUndoState(file)
})
async function fetchWorkspace() {
try {
const workspace = await plugin.call('filePanel', 'getCurrentWorkspace')
if (workspace) value.setCurrentWorkspace(workspace.name)
setFiles(await getDirectory('/', plugin))
} catch (e) {
console.log(e)
}
}
fetchWorkspace()
return () => {
plugin.off('fileManager', 'fileChanged')
plugin.off('filePanel', 'setWorkspace')
}
}, [])
//*.sol, **/*.txt, contracts/*
const setGlobalExpression = (paths: string) => {
const results = []
paths.split(',').forEach(path => {
path = path.trim()
if (path.startsWith('*.')) path = path.replace(/(\*\.)/g, '**/*.')
if (path.endsWith('/*') && !path.endsWith('/**/*'))
path = path.replace(/(\*)/g, '**/*.*')
results.push(path)
})
return results
}
const checkUndoState = async (path: string) => {
if (!plugin) return
try {
const content = await plugin.call('fileManager', 'readFile', path)
const workspace = await plugin.call('filePanel', 'getCurrentWorkspace')
value.setUndoEnabled(path, workspace.name, content)
} catch (e) {
console.log(e)
}
}
const setUndoState = async (
oldContent: string,
newContent: string,
path: string
) => {
const workspace = await plugin.call('filePanel', 'getCurrentWorkspace')
const undo = {
oldContent,
newContent,
path,
workspace: workspace.name
}
dispatch({
type: 'SET_UNDO',
payload: undo
})
}
const createRegExFromFind = () => {
let flags = 'g'
let find = state.find
if (!state.casesensitive) flags += 'i'
if (!state.useRegExp) find = escapeRegExp(find)
if (state.matchWord) find = `\\b${find}\\b`
const re = new RegExp(find, flags)
return re
}
useEffect(() => {
if (state.count > 500) {
value.setClipped(true)
value.cancelSearch(false)
}
}, [state.count])
useEffect(() => {
if (state.find) {
(async () => {
try {
const pathFilter: any = {}
if (state.include) {
pathFilter.include = setGlobalExpression(state.include)
}
if (state.exclude) {
pathFilter.exclude = setGlobalExpression(state.exclude)
}
const filteredFiles = files
.filter(filePathFilter(pathFilter))
.map(file => {
const r: SearchResult = {
filename: file,
lines: [],
path: file,
timeStamp: Date.now(),
forceReload: false,
count: 0
}
return r
})
value.setSearchResults(filteredFiles)
} catch (e) {
console.log(e)
}
})()
}
}, [state.timeStamp])
return (
<>
<SearchContext.Provider value={value}>{children}</SearchContext.Provider>
</>
)
}