Ad isValid to parseURI

This commit is contained in:
Thomas Zarebczan 2020-03-04 23:16:17 -05:00
parent f36b91496b
commit 4bdcd008c7
7 changed files with 148 additions and 141 deletions

107
dist/bundle.es.js vendored
View file

@ -1168,7 +1168,9 @@ const separateQuerystring = new RegExp(queryStringBreaker);
* messages for invalid names. * messages for invalid names.
* *
* Returns a dictionary with keys: * Returns a dictionary with keys:
* - path (string) * - path (string)
* - isValid (boolean)
* - isChannel (boolean) * - isChannel (boolean)
* - streamName (string, if present) * - streamName (string, if present)
* - streamClaimId (string, if present) * - streamClaimId (string, if present)
@ -1200,18 +1202,21 @@ function parseURI(URL, requireProto = false) {
const [proto, ...rest] = regexMatch.slice(1).map(match => match || null); const [proto, ...rest] = regexMatch.slice(1).map(match => match || null);
const path = rest.join(''); const path = rest.join('');
const [streamNameOrChannelName, primaryModSeparator, primaryModValue, pathSep, possibleStreamName, secondaryModSeparator, secondaryModValue] = rest; const [streamNameOrChannelName, primaryModSeparator, primaryModValue, pathSep, possibleStreamName, secondaryModSeparator, secondaryModValue] = rest;
let isValid = true;
// Validate protocol // Validate protocol
if (requireProto && !proto) { if (requireProto && !proto) {
throw new Error(__('LBRY URLs must include a protocol prefix (lbry://).')); isValid = false;
console.log('LBRY URLs must include a protocol prefix (lbry://).');
} }
// Validate and process name // Validate and process name
if (!streamNameOrChannelName) { if (!streamNameOrChannelName) {
throw new Error(__('URL does not include name.')); isValid = false;
console.log('URL does not include name.');
} }
rest.forEach(urlPiece => { rest.forEach(urlPiece => {
isValid = false;
if (urlPiece && urlPiece.includes(' ')) { if (urlPiece && urlPiece.includes(' ')) {
console.error('URL can not include a space'); console.error('URL can not include a space');
} }
@ -1223,24 +1228,30 @@ function parseURI(URL, requireProto = false) {
if (includesChannel) { if (includesChannel) {
if (!channelName) { if (!channelName) {
throw new Error(__('No channel name after @.')); isValid = false;
console.log('No channel name after @.');
} }
if (channelName.length < channelNameMinLength) { if (channelName.length < channelNameMinLength) {
throw new Error(__(`Channel names must be at least %channelNameMinLength% characters.`, { isValid = false;
console.log(`Channel names must be at least %channelNameMinLength% characters.`, {
channelNameMinLength channelNameMinLength
})); });
} }
} }
// Validate and process modifier // Validate and process modifier
const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier(primaryModSeparator, primaryModValue); const [primaryClaimId, primaryClaimSequence, primaryBidPosition, primaryValid] = parseURIModifier(primaryModSeparator, primaryModValue);
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier(secondaryModSeparator, secondaryModValue); const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition, secondaryValid] = parseURIModifier(secondaryModSeparator, secondaryModValue);
if (primaryModSeparator && !primaryValid || secondaryModSeparator && !secondaryValid) isValid = false;
const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName; const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName;
const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId; const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId;
const channelClaimId = includesChannel && primaryClaimId; const channelClaimId = includesChannel && primaryClaimId;
return _extends({ return _extends({
isValid,
isChannel, isChannel,
path path
}, streamName ? { streamName } : {}, streamClaimId ? { streamClaimId } : {}, channelName ? { channelName } : {}, channelClaimId ? { channelClaimId } : {}, primaryClaimSequence ? { primaryClaimSequence: parseInt(primaryClaimSequence, 10) } : {}, secondaryClaimSequence ? { secondaryClaimSequence: parseInt(secondaryClaimSequence, 10) } : {}, primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}, secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}, { }, streamName ? { streamName } : {}, streamClaimId ? { streamClaimId } : {}, channelName ? { channelName } : {}, channelClaimId ? { channelClaimId } : {}, primaryClaimSequence ? { primaryClaimSequence: parseInt(primaryClaimSequence, 10) } : {}, secondaryClaimSequence ? { secondaryClaimSequence: parseInt(secondaryClaimSequence, 10) } : {}, primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}, secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}, {
@ -1256,10 +1267,12 @@ function parseURIModifier(modSeperator, modValue) {
let claimId; let claimId;
let claimSequence; let claimSequence;
let bidPosition; let bidPosition;
let isValid = true;
if (modSeperator) { if (modSeperator) {
if (!modValue) { if (!modValue) {
throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator })); isValid = false;
console.log(`No modifier provided after separator %modSeperator%.`, { modSeperator });
} }
if (modSeperator === '#') { if (modSeperator === '#') {
@ -1272,18 +1285,21 @@ function parseURIModifier(modSeperator, modValue) {
} }
if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) { if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) {
throw new Error(__(`Invalid claim ID %claimId%.`, { claimId })); isValid = false;
console.log(`Invalid claim ID %claimId%.`, { claimId });
} }
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) { if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) {
throw new Error(__('Claim sequence must be a number.')); isValid = false;
console.log('Claim sequence must be a number.');
} }
if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) { if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) {
throw new Error(__('Bid position must be a number.')); isValid = false;
console.log('Bid position must be a number.');
} }
return [claimId, claimSequence, bidPosition]; return [claimId, claimSequence, bidPosition, isValid];
} }
/** /**
@ -1324,6 +1340,7 @@ function buildURI(UrlObj, includeProto = true, protoDefault = 'lbry://') {
/* Takes a parseable LBRY URL and converts it to standard, canonical format */ /* Takes a parseable LBRY URL and converts it to standard, canonical format */
function normalizeURI(URL) { function normalizeURI(URL) {
const { const {
isValid,
streamName, streamName,
streamClaimId, streamClaimId,
channelName, channelName,
@ -1334,7 +1351,7 @@ function normalizeURI(URL) {
secondaryBidPosition secondaryBidPosition
} = parseURI(URL); } = parseURI(URL);
return buildURI({ return isValid && buildURI({
streamName, streamName,
streamClaimId, streamClaimId,
channelName, channelName,
@ -1347,13 +1364,9 @@ function normalizeURI(URL) {
} }
function isURIValid(URL) { function isURIValid(URL) {
try { let isValid;
parseURI(normalizeURI(URL)); ({ isValid } = parseURI(normalizeURI(URL)));
} catch (error) { return isValid;
return false;
}
return true;
} }
function isNameValid(claimName) { function isNameValid(claimName) {
@ -1361,14 +1374,9 @@ function isNameValid(claimName) {
} }
function isURIClaimable(URL) { function isURIClaimable(URL) {
let parts; const { isValid, parts } = parseURI(normalizeURI(URL));
try {
parts = parseURI(normalizeURI(URL));
} catch (error) {
return false;
}
return parts && parts.streamName && !parts.streamClaimId && !parts.isChannel; return isValid && parts && parts.streamName && !parts.streamClaimId && !parts.isChannel;
} }
function convertToShareLink(URL) { function convertToShareLink(URL) {
@ -1445,8 +1453,8 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec
} }
let searchSuggestions = []; let searchSuggestions = [];
try { const uri = normalizeURI(query);
const uri = normalizeURI(query); if (uri) {
const { channelName, streamName, isChannel } = parseURI(uri); const { channelName, streamName, isChannel } = parseURI(uri);
searchSuggestions.push({ searchSuggestions.push({
value: query, value: query,
@ -1456,7 +1464,7 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec
shorthand: isChannel ? channelName : streamName, shorthand: isChannel ? channelName : streamName,
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE
}); });
} catch (e) { } else {
searchSuggestions.push({ searchSuggestions.push({
value: query, value: query,
type: SEARCH_TYPES.SEARCH type: SEARCH_TYPES.SEARCH
@ -1472,16 +1480,16 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec
if (apiSuggestions.length) { if (apiSuggestions.length) {
searchSuggestions = searchSuggestions.concat(apiSuggestions.filter(suggestion => suggestion !== query).map(suggestion => { searchSuggestions = searchSuggestions.concat(apiSuggestions.filter(suggestion => suggestion !== query).map(suggestion => {
// determine if it's a channel // determine if it's a channel
try { const uri = normalizeURI(suggestion);
const uri = normalizeURI(suggestion); if (uri) {
const { channelName, streamName, isChannel } = parseURI(uri); const { isValid, channelName, streamName, isChannel } = parseURI(uri);
return { return {
value: uri, value: uri,
shorthand: isChannel ? channelName : streamName, shorthand: isChannel ? channelName : streamName,
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE
}; };
} catch (e) { } else {
// search result includes some character that isn't valid in claim names // search result includes some character that isn't valid in claim names
return { return {
value: suggestion, value: suggestion,
@ -2031,10 +2039,10 @@ const selectPendingClaims = reselect.createSelector(selectState$2, state => Obje
const makeSelectClaimIsPending = uri => reselect.createSelector(selectPendingById, pendingById => { const makeSelectClaimIsPending = uri => reselect.createSelector(selectPendingById, pendingById => {
let claimId; let claimId;
try { const { isValid, isChannel, channelClaimId, streamClaimId } = parseURI(uri);
const { isChannel, channelClaimId, streamClaimId } = parseURI(uri); if (isValid) {
claimId = isChannel ? channelClaimId : streamClaimId; claimId = isChannel ? channelClaimId : streamClaimId;
} catch (e) {} }
if (claimId) { if (claimId) {
return Boolean(pendingById[claimId]); return Boolean(pendingById[claimId]);
@ -2051,16 +2059,13 @@ const makeSelectClaimForUri = (uri, returnRepost = true) => reselect.createSelec
// Check if a claim is pending first // Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing // It won't be in claimsByUri because resolving it will return nothing
let valid;
let channelClaimId; let channelClaimId;
let streamClaimId; let streamClaimId;
let isChannel; let isChannel;
try { let isValid;
({ isChannel, channelClaimId, streamClaimId } = parseURI(uri)); ({ isValid, isChannel, channelClaimId, streamClaimId } = parseURI(uri));
valid = true;
} catch (e) {}
if (valid && byUri) { if (isValid && byUri) {
const claimId = isChannel ? channelClaimId : streamClaimId; const claimId = isChannel ? channelClaimId : streamClaimId;
const pendingClaim = pendingById[claimId]; const pendingClaim = pendingById[claimId];
@ -2096,18 +2101,12 @@ const selectMyActiveClaims = reselect.createSelector(selectMyClaimsRaw, selectAb
const makeSelectClaimIsMine = rawUri => { const makeSelectClaimIsMine = rawUri => {
let uri; let uri;
try { uri = normalizeURI(rawUri);
uri = normalizeURI(rawUri);
} catch (e) {}
return reselect.createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => { return uri && reselect.createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => {
try { const { isValid } = parseURI(uri);
parseURI(uri);
} catch (e) {
return false;
}
return claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id); return isValid && claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id);
}); });
}; };

View file

@ -1,7 +1,8 @@
// @flow // @flow
declare type LbryUrlObj = { declare type LbryUrlObj = {
// Path and channel will always exist when calling parseURI // Path, channel, and isValid will always exist when calling parseURI
// But they may not exist when code calls buildURI // But they may not exist when code calls buildURI
isValid?: boolean,
isChannel?: boolean, isChannel?: boolean,
path?: string, path?: string,
streamName?: string, streamName?: string,

View file

@ -1,7 +1,8 @@
// @flow // @flow
declare type LbryUrlObj = { declare type LbryUrlObj = {
// Path and channel will always exist when calling parseURI // Path, channel, and isValid will always exist when calling parseURI
// But they may not exist when code calls buildURI // But they may not exist when code calls buildURI
isValid?: boolean,
isChannel?: boolean, isChannel?: boolean,
path?: string, path?: string,
streamName?: string, streamName?: string,

View file

@ -17,7 +17,9 @@ const separateQuerystring = new RegExp(queryStringBreaker);
* messages for invalid names. * messages for invalid names.
* *
* Returns a dictionary with keys: * Returns a dictionary with keys:
* - path (string) * - path (string)
* - isValid (boolean)
* - isChannel (boolean) * - isChannel (boolean)
* - streamName (string, if present) * - streamName (string, if present)
* - streamClaimId (string, if present) * - streamClaimId (string, if present)
@ -60,18 +62,21 @@ export function parseURI(URL: string, requireProto: boolean = false): LbryUrlObj
secondaryModSeparator, secondaryModSeparator,
secondaryModValue, secondaryModValue,
] = rest; ] = rest;
let isValid = true;
// Validate protocol // Validate protocol
if (requireProto && !proto) { if (requireProto && !proto) {
throw new Error(__('LBRY URLs must include a protocol prefix (lbry://).')); isValid = false;
console.log('LBRY URLs must include a protocol prefix (lbry://).');
} }
// Validate and process name // Validate and process name
if (!streamNameOrChannelName) { if (!streamNameOrChannelName) {
throw new Error(__('URL does not include name.')); isValid = false;
console.log('URL does not include name.');
} }
rest.forEach(urlPiece => { rest.forEach(urlPiece => {
isValid = false;
if (urlPiece && urlPiece.includes(' ')) { if (urlPiece && urlPiece.includes(' ')) {
console.error('URL can not include a space'); console.error('URL can not include a space');
} }
@ -83,32 +88,39 @@ export function parseURI(URL: string, requireProto: boolean = false): LbryUrlObj
if (includesChannel) { if (includesChannel) {
if (!channelName) { if (!channelName) {
throw new Error(__('No channel name after @.')); isValid = false;
console.log('No channel name after @.');
} }
if (channelName.length < channelNameMinLength) { if (channelName.length < channelNameMinLength) {
throw new Error( isValid = false;
__(`Channel names must be at least %channelNameMinLength% characters.`, { console.log(`Channel names must be at least %channelNameMinLength% characters.`, {
channelNameMinLength, channelNameMinLength,
}) });
);
} }
} }
// Validate and process modifier // Validate and process modifier
const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier( const [primaryClaimId, primaryClaimSequence, primaryBidPosition, primaryValid] = parseURIModifier(
primaryModSeparator, primaryModSeparator,
primaryModValue primaryModValue
); );
const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier( const [
secondaryModSeparator, secondaryClaimId,
secondaryModValue secondaryClaimSequence,
); secondaryBidPosition,
secondaryValid,
] = parseURIModifier(secondaryModSeparator, secondaryModValue);
if ((primaryModSeparator && !primaryValid) || (secondaryModSeparator && !secondaryValid))
isValid = false;
const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName; const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName;
const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId; const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId;
const channelClaimId = includesChannel && primaryClaimId; const channelClaimId = includesChannel && primaryClaimId;
return { return {
isValid,
isChannel, isChannel,
path, path,
...(streamName ? { streamName } : {}), ...(streamName ? { streamName } : {}),
@ -135,10 +147,12 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) {
let claimId; let claimId;
let claimSequence; let claimSequence;
let bidPosition; let bidPosition;
let isValid = true;
if (modSeperator) { if (modSeperator) {
if (!modValue) { if (!modValue) {
throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator })); isValid = false;
console.log(`No modifier provided after separator %modSeperator%.`, { modSeperator });
} }
if (modSeperator === '#') { if (modSeperator === '#') {
@ -151,18 +165,21 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) {
} }
if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) { if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) {
throw new Error(__(`Invalid claim ID %claimId%.`, { claimId })); isValid = false;
console.log(`Invalid claim ID %claimId%.`, { claimId });
} }
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) { if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) {
throw new Error(__('Claim sequence must be a number.')); isValid = false;
console.log('Claim sequence must be a number.');
} }
if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) { if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) {
throw new Error(__('Bid position must be a number.')); isValid = false;
console.log('Bid position must be a number.');
} }
return [claimId, claimSequence, bidPosition]; return [claimId, claimSequence, bidPosition, isValid];
} }
/** /**
@ -240,6 +257,7 @@ export function buildURI(
/* Takes a parseable LBRY URL and converts it to standard, canonical format */ /* Takes a parseable LBRY URL and converts it to standard, canonical format */
export function normalizeURI(URL: string) { export function normalizeURI(URL: string) {
const { const {
isValid,
streamName, streamName,
streamClaimId, streamClaimId,
channelName, channelName,
@ -250,41 +268,35 @@ export function normalizeURI(URL: string) {
secondaryBidPosition, secondaryBidPosition,
} = parseURI(URL); } = parseURI(URL);
return buildURI({ return (
streamName, isValid &&
streamClaimId, buildURI({
channelName, streamName,
channelClaimId, streamClaimId,
primaryClaimSequence, channelName,
primaryBidPosition, channelClaimId,
secondaryClaimSequence, primaryClaimSequence,
secondaryBidPosition, primaryBidPosition,
}); secondaryClaimSequence,
secondaryBidPosition,
})
);
} }
export function isURIValid(URL: string): boolean { export function isURIValid(URL: string) {
try { let isValid;
parseURI(normalizeURI(URL)); ({ isValid } = parseURI(normalizeURI(URL)));
} catch (error) { return isValid;
return false;
}
return true;
} }
export function isNameValid(claimName: string) { export function isNameValid(claimName: string) {
return !regexInvalidURI.test(claimName); return !regexInvalidURI.test(claimName);
} }
export function isURIClaimable(URL: string) { export function isURIClaimable(URL: string): boolean {
let parts; const { isValid, parts } = parseURI(normalizeURI(URL));
try {
parts = parseURI(normalizeURI(URL));
} catch (error) {
return false;
}
return parts && parts.streamName && !parts.streamClaimId && !parts.isChannel; return isValid && parts && parts.streamName && !parts.streamClaimId && !parts.isChannel;
} }
export function convertToShareLink(URL: string) { export function convertToShareLink(URL: string) {

View file

@ -9,7 +9,7 @@
// - Sean // - Sean
import * as ACTIONS from 'constants/action_types'; import * as ACTIONS from 'constants/action_types';
import { buildURI, parseURI } from 'lbryURI'; import { buildURI } from 'lbryURI';
import { concatClaims } from 'util/claim'; import { concatClaims } from 'util/claim';
type State = { type State = {

View file

@ -86,10 +86,10 @@ export const makeSelectClaimIsPending = (uri: string) =>
pendingById => { pendingById => {
let claimId; let claimId;
try { const { isValid, isChannel, channelClaimId, streamClaimId } = parseURI(uri);
const { isChannel, channelClaimId, streamClaimId } = parseURI(uri); if (isValid) {
claimId = isChannel ? channelClaimId : streamClaimId; claimId = isChannel ? channelClaimId : streamClaimId;
} catch (e) {} }
if (claimId) { if (claimId) {
return Boolean(pendingById[claimId]); return Boolean(pendingById[claimId]);
@ -115,16 +115,13 @@ export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true)
// Check if a claim is pending first // Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing // It won't be in claimsByUri because resolving it will return nothing
let valid;
let channelClaimId; let channelClaimId;
let streamClaimId; let streamClaimId;
let isChannel; let isChannel;
try { let isValid;
({ isChannel, channelClaimId, streamClaimId } = parseURI(uri)); ({ isValid, isChannel, channelClaimId, streamClaimId } = parseURI(uri));
valid = true;
} catch (e) {}
if (valid && byUri) { if (isValid && byUri) {
const claimId = isChannel ? channelClaimId : streamClaimId; const claimId = isChannel ? channelClaimId : streamClaimId;
const pendingClaim = pendingById[claimId]; const pendingClaim = pendingById[claimId];
@ -178,22 +175,25 @@ export const selectMyActiveClaims = createSelector(
export const makeSelectClaimIsMine = (rawUri: string) => { export const makeSelectClaimIsMine = (rawUri: string) => {
let uri; let uri;
try { uri = normalizeURI(rawUri);
uri = normalizeURI(rawUri);
} catch (e) {}
return createSelector( return (
selectClaimsByUri, uri &&
selectMyActiveClaims, createSelector(
(claims, myClaims) => { selectClaimsByUri,
try { selectMyActiveClaims,
parseURI(uri); (claims, myClaims) => {
} catch (e) { const { isValid } = parseURI(uri);
return false;
return (
isValid &&
claims &&
claims[uri] &&
claims[uri].claim_id &&
myClaims.has(claims[uri].claim_id)
);
} }
)
return claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id);
}
); );
}; };

View file

@ -106,8 +106,8 @@ export const selectSearchSuggestions: Array<SearchSuggestion> = createSelector(
} }
let searchSuggestions = []; let searchSuggestions = [];
try { const uri = normalizeURI(query);
const uri = normalizeURI(query); if (uri) {
const { channelName, streamName, isChannel } = parseURI(uri); const { channelName, streamName, isChannel } = parseURI(uri);
searchSuggestions.push( searchSuggestions.push(
{ {
@ -120,7 +120,7 @@ export const selectSearchSuggestions: Array<SearchSuggestion> = createSelector(
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE,
} }
); );
} catch (e) { } else {
searchSuggestions.push({ searchSuggestions.push({
value: query, value: query,
type: SEARCH_TYPES.SEARCH, type: SEARCH_TYPES.SEARCH,
@ -139,16 +139,16 @@ export const selectSearchSuggestions: Array<SearchSuggestion> = createSelector(
.filter(suggestion => suggestion !== query) .filter(suggestion => suggestion !== query)
.map(suggestion => { .map(suggestion => {
// determine if it's a channel // determine if it's a channel
try { const uri = normalizeURI(suggestion);
const uri = normalizeURI(suggestion); if (uri) {
const { channelName, streamName, isChannel } = parseURI(uri); const { isValid, channelName, streamName, isChannel } = parseURI(uri);
return { return {
value: uri, value: uri,
shorthand: isChannel ? channelName : streamName, shorthand: isChannel ? channelName : streamName,
type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE,
}; };
} catch (e) { } else {
// search result includes some character that isn't valid in claim names // search result includes some character that isn't valid in claim names
return { return {
value: suggestion, value: suggestion,
@ -172,21 +172,15 @@ type CustomOptions = {
from?: number, from?: number,
related_to?: string, related_to?: string,
nsfw?: boolean, nsfw?: boolean,
} };
export const makeSelectQueryWithOptions = ( export const makeSelectQueryWithOptions = (customQuery: ?string, options: CustomOptions) =>
customQuery: ?string,
options: CustomOptions,
) =>
createSelector( createSelector(
selectSearchValue, selectSearchValue,
selectSearchOptions, selectSearchOptions,
(query, defaultOptions) => { (query, defaultOptions) => {
const searchOptions = { ...defaultOptions, ...options }; const searchOptions = { ...defaultOptions, ...options };
const queryString = getSearchQueryString( const queryString = getSearchQueryString(customQuery || query, searchOptions);
customQuery || query,
searchOptions,
);
return queryString; return queryString;
} }