Refactor lbryuri.js into separate named exports #957

Merged
IGassmann merged 1 commit from issue/952 into master 2018-01-22 19:25:04 +01:00
23 changed files with 80 additions and 88 deletions

View file

@ -1,5 +1,5 @@
import React from 'react';
import lbryuri from 'lbryuri.js';
import { normalizeURI } from 'lbryURI';
import CardMedia from 'component/cardMedia';
import Link from 'component/link';
import { TruncatedText } from 'component/common';
@ -57,7 +57,7 @@ class FileCard extends React.PureComponent {
rewardedContentClaimIds,
} = this.props;
const uri = lbryuri.normalize(this.props.uri);
const uri = normalizeURI(this.props.uri);
const title = metadata && metadata.title ? metadata.title : uri;
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;

View file

@ -1,5 +1,5 @@
import React from 'react';
import lbryuri from 'lbryuri.js';
import { buildURI } from 'lbryURI';
import FormField from 'component/formField';
import FileTile from 'component/fileTile';
import { BusyMessage } from 'component/common.js';
@ -76,7 +76,7 @@ class FileList extends React.PureComponent {
uriParams.claimId = fileInfo.claim_id;
uriParams.name = fileInfo.name;
}
const uri = lbryuri.build(uriParams);
const uri = buildURI(uriParams);
content.push(
<FileTile

View file

@ -3,7 +3,7 @@ import FileTile from 'component/fileTile';
import ChannelTile from 'component/channelTile';
import Link from 'component/link';
import { BusyMessage } from 'component/common.js';
import lbryuri from 'lbryuri';
import { parseURI } from 'lbryURI';
const SearchNoResults = props => {
const { query } = props;
@ -45,7 +45,7 @@ class FileListSearch extends React.PureComponent {
{uris && uris.length
? uris.map(
uri =>
lbryuri.parse(uri).name[0] === '@' ? (
parseURI(uri).name[0] === '@' ? (
<ChannelTile key={uri} uri={uri} />
) : (
<FileTile key={uri} uri={uri} />

View file

@ -1,6 +1,6 @@
import React from 'react';
import * as icons from 'constants/icons';
import lbryuri from 'lbryuri.js';
import { normalizeURI, isURIClaimable, parseURI } from 'lbryURI';
import CardMedia from 'component/cardMedia';
import { TruncatedText } from 'component/common.js';
import FilePrice from 'component/filePrice';
@ -65,11 +65,11 @@ class FileTile extends React.PureComponent {
fileInfo,
} = this.props;
const uri = lbryuri.normalize(this.props.uri);
const uri = normalizeURI(this.props.uri);
const isClaimed = !!claim;
const isClaimable = lbryuri.isClaimable(uri);
const isClaimable = isURIClaimable(uri);
const title =
isClaimed && metadata && metadata.title ? metadata.title : lbryuri.parse(uri).contentName;
isClaimed && metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);

View file

@ -1,5 +1,5 @@
import React from 'react';
import lbryuri from 'lbryuri';
import { isNameValid } from 'lbryURI';
import { FormRow } from 'component/form.js';
import { BusyMessage } from 'component/common';
import Link from 'component/link';
@ -29,7 +29,7 @@ class ChannelSection extends React.PureComponent {
? event.target.value
: `@${event.target.value}`;
if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) {
if (newChannelName.length > 1 && !isNameValid(newChannelName.substr(1), false)) {
this.refs.newChannelName.showError(
__('LBRY channel names must contain only letters, numbers and dashes.')
);

View file

@ -1,6 +1,6 @@
import React from 'react';
import lbry from 'lbry';
import lbryuri from 'lbryuri';
import { isNameValid, buildURI, regexInvalidURI } from 'lbryURI';
import FormField from 'component/formField';
import { Form, FormRow, Submit } from 'component/form.js';
import Link from 'component/link';
@ -245,7 +245,7 @@ class PublishForm extends React.PureComponent {
return;
}
if (!lbryuri.isValidName(rawName, false)) {
if (!isNameValid(rawName, false)) {
this.refs.name.showError(__('LBRY names must contain only letters, numbers and dashes.'));
return;
}
@ -254,7 +254,7 @@ class PublishForm extends React.PureComponent {
if (this.state.channel !== 'anonymous') channel = this.state.channel;
const name = rawName.toLowerCase();
const uri = lbryuri.build({ contentName: name, channelName: channel });
const uri = buildURI({ contentName: name, channelName: channel });
this.setState({
rawName,
name,
@ -446,7 +446,7 @@ class PublishForm extends React.PureComponent {
const extension = path.extname(fileName);
fileName = path.basename(fileName, extension);
fileName = fileName.replace(lbryuri.REGEXP_INVALID_URI, '');
fileName = fileName.replace(regexInvalidURI, '');
return fileName;
}

View file

@ -3,7 +3,7 @@ import LinkTransaction from 'component/linkTransaction';
import { CreditAmount } from 'component/common';
import DateTime from 'component/dateTime';
import Link from 'component/link';
import lbryuri from 'lbryuri';
import { buildURI } from 'lbryURI';
import * as txnTypes from 'constants/transaction_types';
class TransactionListItem extends React.PureComponent {
@ -74,7 +74,7 @@ class TransactionListItem extends React.PureComponent {
<Link
className="button-text"
navigate="/show"
navigateParams={{ uri: lbryuri.build({ name, claimId }) }}
navigateParams={{ uri: buildURI({ name, claimId }) }}
>
{name}
</Link>

View file

@ -1,5 +1,5 @@
import React from 'react';
import lbryuri from 'lbryuri';
import { normalizeURI } from 'lbryURI';
import { connect } from 'react-redux';
import { doResolveUri } from 'redux/actions/content';
import { makeSelectIsUriResolving } from 'redux/selectors/content';
@ -9,7 +9,7 @@ import UriIndicator from './view';
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
uri: lbryuri.normalize(props.uri),
uri: normalizeURI(props.uri),
});
const perform = dispatch => ({

View file

@ -1,7 +1,7 @@
import React from 'react';
import Icon from 'component/icon';
import Link from 'component/link';
import lbryuri from 'lbryuri';
import { buildURI } from 'lbryURI';
import classnames from 'classnames';
class UriIndicator extends React.PureComponent {
@ -49,7 +49,7 @@ class UriIndicator extends React.PureComponent {
if (signatureIsValid) {
modifier = 'valid';
channelLink = link ? lbryuri.build({ channelName, claimId: channelClaimId }, false) : false;
channelLink = link ? buildURI({ channelName, claimId: channelClaimId }, false) : false;
} else {
icon = 'icon-times-circle';
modifier = 'invalid';

View file

@ -1,6 +1,6 @@
import React from 'react';
import { Form, FormRow, Submit } from 'component/form';
import lbryuri from 'lbryuri';
import { regexAddress } from 'lbryURI';
class WalletSend extends React.PureComponent {
handleSubmit() {
@ -42,7 +42,7 @@ class WalletSend extends React.PureComponent {
size="60"
onChange={setAddress}
value={address}
regexp={lbryuri.REGEXP_ADDRESS}
regexp={regexAddress}
trim
/>
<div className="form-row-submit">

View file

@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import lbryuri from 'lbryuri.js';
import { normalizeURI } from 'lbryURI.js';
import { selectWunderBarAddress, selectWunderBarIcon } from 'redux/selectors/search';
import { doNavigate } from 'redux/actions/navigation';
import Wunderbar from './view';
@ -13,7 +13,7 @@ const select = state => ({
const perform = dispatch => ({
onSearch: query => dispatch(doNavigate('/search', { query })),
onSubmit: (query, extraParams) =>
dispatch(doNavigate('/show', { uri: lbryuri.normalize(query), ...extraParams })),
dispatch(doNavigate('/show', { uri: normalizeURI(query), ...extraParams })),
});
export default connect(select, perform)(Wunderbar);

View file

@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import lbryuri from 'lbryuri.js';
import { normalizeURI } from 'lbryURI';
import Icon from 'component/icon';
import { parseQueryParams } from 'util/query_params';
@ -130,7 +130,7 @@ class WunderBar extends React.PureComponent {
if (parts.length > 0) extraParams = parseQueryParams(parts.join(''));
try {
uri = lbryuri.normalize(value);
uri = normalizeURI(value);
this.setState({ value: uri });
} catch (error) {
// then it's not a valid URL, so let's search

View file

@ -1,10 +1,8 @@
const CHANNEL_NAME_MIN_LEN = 1;
const CLAIM_ID_MAX_LEN = 40;
const channelNameMinLength = 1;
const claimIdMaxLength = 40;
const Lbryuri = {};
Lbryuri.REGEXP_INVALID_URI = /[^A-Za-z0-9-]/g;
Lbryuri.REGEXP_ADDRESS = /^b(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
export const regexInvalidURI = /[^A-Za-z0-9-]/g;
export const regexAddress = /^b(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
/**
* Parses a LBRY name into its component parts. Throws errors with user-friendly
@ -28,7 +26,7 @@ Lbryuri.REGEXP_ADDRESS = /^b(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
* - contentName (string): For anon claims, the name; for channel claims, the path
* - channelName (string, if present): Channel name without @
*/
Lbryuri.parse = (uri, requireProto = false) => {
export function parseURI(URI, requireProto = false) {
// Break into components. Empty sub-matches are converted to null
const componentsRegex = new RegExp(
'^((?:lbry://)?)' + // protocol
@ -37,7 +35,7 @@ Lbryuri.parse = (uri, requireProto = false) => {
'(/?)(.*)' // path separator, path
);
const [proto, name, modSep, modVal, pathSep, path] = componentsRegex
.exec(uri)
.exec(URI)
.slice(1)
.map(match => match || null);
@ -61,14 +59,14 @@ Lbryuri.parse = (uri, requireProto = false) => {
throw new Error(__('No channel name after @.'));
}
if (channelName.length < CHANNEL_NAME_MIN_LEN) {
throw new Error(__(`Channel names must be at least %s characters.`, CHANNEL_NAME_MIN_LEN));
if (channelName.length < channelNameMinLength) {
throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength));
}
contentName = path;
}
const nameBadChars = (channelName || name).match(Lbryuri.REGEXP_INVALID_URI);
const nameBadChars = (channelName || name).match(regexInvalidURI);
if (nameBadChars) {
throw new Error(
__(
@ -99,7 +97,7 @@ Lbryuri.parse = (uri, requireProto = false) => {
if (
claimId &&
(claimId.length > CLAIM_ID_MAX_LEN || !claimId.match(/^[0-9a-f]+$/)) &&
(claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/)) &&
!claimId.match(/^pending/) // ought to be dropped when savePendingPublish drops hack
) {
throw new Error(__(`Invalid claim ID %s.`, claimId));
@ -119,7 +117,7 @@ Lbryuri.parse = (uri, requireProto = false) => {
throw new Error(__('Only channel URIs may have a path.'));
}
const pathBadChars = path.match(Lbryuri.REGEXP_INVALID_URI);
const pathBadChars = path.match(regexInvalidURI);
if (pathBadChars) {
throw new Error(__(`Invalid character in path: %s`, pathBadChars.join(', ')));
}
@ -140,17 +138,17 @@ Lbryuri.parse = (uri, requireProto = false) => {
...(claimId ? { claimId } : {}),
...(path ? { path } : {}),
};
};
}
/**
* Takes an object in the same format returned by lbryuri.parse() and builds a URI.
* Takes an object in the same format returned by parse() and builds a URI.
*
* The channelName key will accept names with or without the @ prefix.
*/
Lbryuri.build = (uriObj, includeProto = true) => {
const { claimId, claimSequence, bidPosition, contentName, channelName } = uriObj;
export function buildURI(URIObj, includeProto = true) {
const { claimId, claimSequence, bidPosition, contentName, channelName } = URIObj;
let { name, path } = uriObj;
let { name, path } = URIObj;
if (channelName) {
const channelNameFormatted = channelName.startsWith('@') ? channelName : `@${channelName}`;
@ -188,36 +186,35 @@ Lbryuri.build = (uriObj, includeProto = true) => {
(bidPosition ? `${bidPosition}` : '') +
(path ? `/${path}` : '')
);
};
}
/* Takes a parseable LBRY URI and converts it to standard, canonical format (currently this just
* consists of adding the lbry:// prefix if needed) */
Lbryuri.normalize = uri => {
if (uri.match(/pending_claim/)) return uri;
/* Takes a parseable LBRY URI and converts it to standard, canonical format */
export function normalizeURI(URI) {
if (URI.match(/pending_claim/)) return URI;
const { name, path, bidPosition, claimSequence, claimId } = Lbryuri.parse(uri);
return Lbryuri.build({ name, path, claimSequence, bidPosition, claimId });
};
const { name, path, bidPosition, claimSequence, claimId } = parseURI(URI);
return buildURI({ name, path, claimSequence, bidPosition, claimId });
}
Lbryuri.isValid = uri => {
export function isURIValid(URI) {
let parts;
try {
parts = Lbryuri.parse(Lbryuri.normalize(uri));
parts = parseURI(normalizeURI(URI));
} catch (error) {
return false;
}
return parts && parts.name;
};
}
Lbryuri.isValidName = (name, checkCase = true) => {
export function isNameValid(name, checkCase = true) {
const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i');
return regexp.test(name);
};
}
Lbryuri.isClaimable = uri => {
export function isURIClaimable(URI) {
let parts;
try {
parts = Lbryuri.parse(Lbryuri.normalize(uri));
parts = parseURI(normalizeURI(URI));
} catch (error) {
return false;
}
@ -230,7 +227,4 @@ Lbryuri.isClaimable = uri => {
!parts.isChannel &&
!parts.path
);
};
window.lbryuri = Lbryuri;
export default Lbryuri;
}

View file

@ -1,5 +1,5 @@
import React from 'react';
import lbryuri from 'lbryuri';
import { buildURI } from 'lbryURI';
import { BusyMessage } from 'component/common';
import FileTile from 'component/fileTile';
import ReactPaginate from 'react-paginate';
@ -46,7 +46,7 @@ class ChannelPage extends React.PureComponent {
} = this.props;
const { name, claim_id: claimId } = claim;
const subscriptionUri = lbryuri.build({ channelName: name, claimId }, false);
const subscriptionUri = buildURI({ channelName: name, claimId }, false);
let contentList;
if (fetching) {
@ -57,7 +57,7 @@ class ChannelPage extends React.PureComponent {
claimsInChannel.map(claim => (
<FileTile
key={claim.claim_id}
uri={lbryuri.build({
uri={buildURI({
name: claim.name,
claimId: claim.claim_id,
})}

View file

@ -1,6 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import lbryuri from 'lbryuri';
import { normalizeURI } from 'lbryURI';
import FileCard from 'component/fileCard';
import { BusyMessage } from 'component/common.js';
import Icon from 'component/icon';
@ -212,7 +212,7 @@ export class FeaturedCategory extends React.PureComponent {
<div ref="rowitems" className="card-row__items">
{names &&
names.map(name => (
<FileCard key={name} displayStyle="card" uri={lbryuri.normalize(name)} />
<FileCard key={name} displayStyle="card" uri={normalizeURI(name)} />
))}
</div>
</div>

View file

@ -1,6 +1,6 @@
import React from 'react';
import lbry from 'lbry';
import lbryuri from 'lbryuri';
import { buildURI, normalizeURI } from 'lbryURI';
import Video from 'component/video';
import { Thumbnail } from 'component/common';
import FilePrice from 'component/filePrice';
@ -65,7 +65,7 @@ class FilePage extends React.PureComponent {
let subscriptionUri;
if (channelName && channelClaimId) {
subscriptionUri = lbryuri.build({ channelName, claimId: channelClaimId }, false);
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
}
return (
@ -86,7 +86,7 @@ class FilePage extends React.PureComponent {
<div className="card__title-identity">
{!fileInfo || fileInfo.written_bytes <= 0 ? (
<span style={{ float: 'right' }}>
<FilePrice uri={lbryuri.normalize(uri)} />
<FilePrice uri={normalizeURI(uri)} />
{isRewardContent && (
<span>
{' '}

View file

@ -1,5 +1,5 @@
import React from 'react';
import lbryuri from 'lbryuri';
import { isURIValid, normalizeURI } from 'lbryURI';
import FileTile from 'component/fileTile';
import FileListSearch from 'component/fileListSearch';
import { ToolTip } from 'component/tooltip.js';
@ -10,7 +10,7 @@ class SearchPage extends React.PureComponent {
return (
<main className="main--single-column">
{lbryuri.isValid(query) ? (
{isURIValid(query) ? (
<section className="section-spaced">
<h3 className="card-row__header">
{__('Exact URL')}{' '}
@ -20,7 +20,7 @@ class SearchPage extends React.PureComponent {
className="tooltip--header"
/>
</h3>
<FileTile uri={lbryuri.normalize(query)} showEmpty={FileTile.SHOW_EMPTY_PUBLISH} />
<FileTile uri={normalizeURI(query)} showEmpty={FileTile.SHOW_EMPTY_PUBLISH} />
</section>
) : (
''

View file

@ -1,5 +1,4 @@
import React from 'react';
import lbryuri from 'lbryuri';
import { BusyMessage } from 'component/common';
import ChannelPage from 'page/channel';
import FilePage from 'page/file';

View file

@ -4,7 +4,7 @@ import * as SETTINGS from 'constants/settings';
import { ipcRenderer } from 'electron';
import Lbry from 'lbry';
import Lbryio from 'lbryio';
import Lbryuri from 'lbryuri';
import { normalizeURI, buildURI } from 'lbryURI';
import { doAlertError, doOpenModal } from 'redux/actions/app';
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
import { selectBadgeNumber } from 'redux/selectors/app';
@ -26,7 +26,7 @@ const DOWNLOAD_POLL_INTERVAL = 250;
export function doResolveUris(uris) {
return (dispatch, getState) => {
const normalizedUris = uris.map(Lbryuri.normalize);
const normalizedUris = uris.map(normalizeURI);
const state = getState();
// Filter out URIs that are already resolving
@ -506,7 +506,7 @@ export function doAbandonClaim(txid, nout) {
claimId,
},
});
dispatch(doResolveUri(Lbryuri.build({ name, claimId })));
dispatch(doResolveUri(buildURI({ name, claimId })));
dispatch(doFetchClaimListMine());
} else {
dispatch(doOpenModal(MODALS.TRANSACTION_FAILED));

View file

@ -1,5 +1,5 @@
import * as ACTIONS from 'constants/action_types';
import Lbryuri from 'lbryuri';
import { buildURI } from 'lbryURI';
import { doResolveUri } from 'redux/actions/content';
import { doNavigate } from 'redux/actions/navigation';
import { selectCurrentPage } from 'redux/selectors/navigation';
@ -40,7 +40,7 @@ export function doSearch(rawQuery) {
const actions = [];
data.forEach(result => {
const uri = Lbryuri.build({
const uri = buildURI({
name: result.name,
claimId: result.claimId,
});

View file

@ -1,4 +1,4 @@
import Lbryuri from 'lbryuri';
import { normalizeURI } from 'lbryURI';
import { makeSelectCurrentParam } from 'redux/selectors/navigation';
import { createSelector } from 'reselect';
@ -32,7 +32,7 @@ export const selectAllClaimsByChannel = createSelector(
);
export const makeSelectClaimForUri = uri =>
createSelector(selectClaimsByUri, claims => claims && claims[Lbryuri.normalize(uri)]);
createSelector(selectClaimsByUri, claims => claims && claims[normalizeURI(uri)]);
export const selectMyClaimsRaw = createSelector(selectState, state => state.myClaims);
@ -53,7 +53,7 @@ export const selectMyActiveClaims = createSelector(
);
export const makeSelectClaimIsMine = rawUri => {
const uri = Lbryuri.normalize(rawUri);
const uri = normalizeURI(rawUri);
return createSelector(
selectClaimsByUri,
selectMyActiveClaims,

View file

@ -1,6 +1,5 @@
import * as settings from 'constants/settings';
import { createSelector } from 'reselect';
import lbryuri from 'lbryuri';
import { makeSelectClaimForUri } from 'redux/selectors/claims';
const _selectState = state => state.media || {};

View file

@ -1,6 +1,6 @@
import { createSelector } from 'reselect';
import { parseQueryParams, toQueryString } from 'util/query_params';
import Lbryuri from 'lbryuri';
import { normalizeURI } from 'lbryURI';
export const selectState = state => state.navigation || {};
@ -93,7 +93,7 @@ export const selectPageTitle = createSelector(
case 'developer':
return __('Developer');
case 'show': {
const parts = [Lbryuri.normalize(params.uri)];
const parts = [normalizeURI(params.uri)];
// If the params has any keys other than "uri"
if (Object.keys(params).length > 1) {
parts.push(toQueryString(Object.assign({}, params, { uri: null })));