[linkifyjs] re-write definitions (#38900)

This commit is contained in:
Gareth Jones
2019-11-01 11:21:32 -07:00
committed by Jesse Trinity
parent 7eb9f13d9b
commit 5c4d11dd09
8 changed files with 220 additions and 390 deletions
+23 -3
View File
@@ -1,4 +1,24 @@
import { LinkifyOptions } from "./index";
import { Options as CommonOptions, LinkEntityType } from './index';
export function linkifyElement(element: HTMLElement, options?: LinkifyOptions, doc?: HTMLDocument): HTMLElement;
export default linkifyElement;
export interface Options extends CommonOptions {
/**
* Add event listeners to newly created link elements.
* Takes a hash where each key is an standard event name and the value is an event handler.
*
* Also accepts a function that takes the unformatted href and the link type (e.g., 'url', 'email', etc.) and returns the hash.
*
* @default null
*/
events?: Partial<GlobalEventHandlers> | ((href: string, type: LinkEntityType) => Partial<GlobalEventHandlers>);
/**
* Prevent linkify from trying to parse links in the specified tags.
*
* This is useful when running linkify on arbitrary HTML.
*
* @default []
*/
ignoreTags?: string[];
}
export default function linkifyElement(element: HTMLElement, options?: Options, doc?: HTMLDocument): HTMLElement;
+23 -3
View File
@@ -1,4 +1,24 @@
import { LinkifyOptions } from "./index";
import { Options as CommonOptions, LinkEntityType } from './index';
export function linkifyHtml(input: string, options?: LinkifyOptions): string;
export default linkifyHtml;
export interface Options extends CommonOptions {
/**
* Add event listeners to newly created link elements.
* Takes a hash where each key is an standard event name and the value is an event handler.
*
* Also accepts a function that takes the unformatted href and the link type (e.g., 'url', 'email', etc.) and returns the hash.
*
* @default null
*/
events?: Partial<GlobalEventHandlers> | ((href: string, type: LinkEntityType) => Partial<GlobalEventHandlers>);
/**
* Prevent linkify from trying to parse links in the specified tags.
*
* This is useful when running linkify on arbitrary HTML.
*
* @default []
*/
ignoreTags?: string[];
}
export default function linkifyHtml(input: string, options?: Options): string;
+93 -113
View File
@@ -1,43 +1,76 @@
// Type definitions for linkifyjs 2.1
// Project: https://github.com/SoapBox/linkifyjs#readme
// Definitions by: Sean Zhu <https://github.com/szhu>
// Definitions by: Gareth Jones <https://github.com/g-rath>
// Sean Zhu <https://github.com/szhu>
// Ovidiu Bute <https://github.com/ovidiubute>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import * as React from "react";
export type LinkEntityType =
| 'url'
| 'email'
| 'hashtag'
| 'mention'
;
export type PossiblyFuncOfHrefAndType<T> =
| T
| ((href: string, type: string) => T);
export interface FindResultHash {
/**
* The type of entity found.
*/
type: LinkEntityType;
/**
* The original entity substring.
*/
value: string;
/**
* Should be the value of this links `href` attribute.
*/
href: string;
}
// There's always a possibility that values at a string key can always be
// undefined; i.e., if the key does not exist.
export type PossiblyByType<T> = T | { [type: string]: T | undefined };
/**
* Finds all links in the given string.
*
* Returns a list of links where each element is a hash.
*
* @param str Search string.
* @param [type] only find links of the given type.
*/
export function find(str: string, type?: LinkEntityType): FindResultHash[];
export type EventHandler = (e: HTMLElement) => void;
/**
* Is the given string a link? Not to be used for strict validation.
*
* @param str the `string` to test.
* @param type returns `true` only if the link is of the given type.
*
* @see https://soapbox.github.io/linkifyjs/docs/caveats.html
*/
export function test(str: string, type?: LinkEntityType): boolean;
export interface LinkifyOptions {
/**
* Internal method used to perform lexicographical analysis on the given string,
* and output the resulting token array.
*
* @param str
*
* @return
*/
export function tokenize(str: string): Array<{ v: Array<{ v: string }> }>;
export interface Options {
/**
* attributes
* - Type: Object | Function (String href, String type)
* - Default: null
*
* Object of attributes to add to each new link. Note: the class and target
* attributes have dedicated options.
*
* Also accepts a function that takes the unformatted href, the link type
* (e.g., 'url', 'email', etc.) and returns the object.
*
* @default null
*/
attributes?: PossiblyFuncOfHrefAndType<
React.AnchorHTMLAttributes<HTMLAnchorElement>
> | null;
attributes?: Record<string, string> | ((href: string, type: LinkEntityType) => Record<string, string>) | null;
/**
* className
* - Type: String | Function (String href, String type) | Object
* - Default: 'linkified' (may be removed in future releases)
*
* class attribute to use for newly created links.
*
* Accepts a function that takes the unformatted href value and link type
@@ -46,129 +79,73 @@ export interface LinkifyOptions {
* Accepts an object where each key is the link type and each value is the
* string or function to use for that type.
*/
className?: PossiblyByType<PossiblyFuncOfHrefAndType<string | undefined>>;
className?: string | Partial<Record<LinkEntityType, string | ((href: string) => string)>> | ((href: string, type: LinkEntityType) => string);
/**
* defaultProtocol
* - Type: String
* - Default: 'http'
* - Values: 'http', 'https', 'ftp', 'ftps', etc.
*
* Protocol that should be used in href attributes for URLs without a
* protocol (e.g., github.com).
*
* @default 'http'
*/
defaultProtocol?: string;
defaultProtocol?: 'http' | 'https' | 'ftp' | 'ftps' | string;
/**
* events
* - *element, jquery interfaces only*
* - Type: Object | Function (String href, String type) | Object
* - Default: null
* Format the text displayed by a linkified entity. e.g., truncate a long URL.
*
* Add event listeners to newly created link elements. Takes a hash where
* each key is an standard event name and the value is an event handler.
* Accepts an object where each key is the link type (e.g., 'url', 'email', etc.),
* and each value is the formatting function to use for that type.
*
* Also accepts a function that takes the unformatted href and the link type
* (e.g., 'url', 'email', etc.) and returns the hash.
*
* For React, specify events in the attributes option as standard React
* events.
*
* See the React Event docs and the linkify-react event docs
* @default null
*/
events?: PossiblyFuncOfHrefAndType<{
[eventName: string]: EventHandler;
}> | null;
format?: ((value: string, type: LinkEntityType) => string) | Partial<Record<LinkEntityType, (value: string) => string>> | null;
/**
* format
* - Type: Function (String value, String type) | Object
* - Default: null
*
* Format the text displayed by a linkified entity. e.g., truncate a long
* URL.
*
* Accepts an object where each key is the link type (e.g., 'url', 'email',
* etc.) and each value is the formatting function to use for that type.
*
* NOTE: According to the linkifyjs implementation, `format` can be just a
* string, but this is not mentioned in the docs, so we exclude it.
*/
format?: PossiblyByType<(value: string, type: string) => string>;
//
/**
* formatHref
* - Type: Function (String href, String type) | Object
* - Default: null
*
* Similar to format, except the result of this function will be used as the
* href attribute of the new link.
*
* This is useful when finding hashtags, where you don’t necessarily want
* the default to be a link to a named anchor.
* This is useful when finding hashtags, where you don’t necessarily
* want the default to be a link to a named anchor.
*
* Accepts an object where each key is the link type (e.g., 'url', 'email',
* etc.) and each value is the formatting function to use for that type.
* Accepts an object where each key is the link type (e.g., 'url', 'email', etc.),
* and each value is the formatting function to use for that type.
*
* NOTE: According to the linkifyjs implementation, `formatHref` can be just
* a string, but this is not mentioned in the docs, so we exclude it.
* @default null
*/
formatHref?: PossiblyByType<(href: string, type: string) => string>;
formatHref?: ((href: string, type: LinkEntityType) => string) | Partial<Record<LinkEntityType, (href: string) => string>> | null;
/**
* ignoreTags
* - *element, html, and jquery interfaces only*
* - Type: Array
* - Default: []
*
* Prevent linkify from trying to parse links in the specified tags. This is
* useful when running linkify on arbitrary HTML.
*/
ignoreTags?: string[];
/**
* nl2br
* - Type: Boolean
* - Default: false
*
* If true, \n line breaks will automatically be converted to <br> tags.
* If `true`, \n line breaks will automatically be converted to `<br>` tags.
*
* @default false
*/
nl2br?: boolean;
/**
* tagName
* - Type: String | Function (String href, String type) | Object
* - Default: a
* The tag name to use for each link.
* For cases where you can’t use anchor tags.
*
* The tag name to use for each link. For cases where you can’t use anchor
* tags.
* Accepts a function that takes the unformatted href,
* the link type (e.g., 'url', 'email', etc.) and returns the tag name.
*
* Accepts a function that takes the unformatted href, the link type (e.g.,
* 'url', 'email', etc.) and returns the tag name.
* Accepts an object where each key is the link type,
* and each value is the tag name to use for that type.
*
* Accepts an object where each key is the link type and each value is the
* tag name to use for that type.
* @default a
*/
tagName?: PossiblyByType<PossiblyFuncOfHrefAndType<string>>;
tagName?: string | ((href: string, type: LinkEntityType) => string) | Partial<Record<LinkEntityType, string>>;
/**
* target
* - Type: String | Function (String href, String type) | Object
* - Default: '_blank' for URLs, null for everything else
*
* target attribute for generated link.
*
* Accepts a function that takes the unformatted href, the link type (e.g.,
* 'url', 'email', etc.) and returns the target
* Accepts a function that takes the unformatted href,
* the link type (e.g., 'url', 'email', etc.) and returns the target
*
* Accepts an object where each key is the link type and each value is the
* target to use for that type.
* Accepts an object where each key is the link type,
* and each value is the target to use for that type.
*
* @default { url: '_blank' }
*/
target?: PossiblyByType<
PossiblyFuncOfHrefAndType<string | null | undefined>
>;
target?: string | ((href: string, type: LinkEntityType) => string) | Partial<Record<LinkEntityType, string | null>>;
/**
* validate
@@ -177,12 +154,15 @@ export interface LinkifyOptions {
*
* If option resolves to false, the given value will not show up as a link.
*
* Accepts a function that takes a discovered link and the link type (e.g.,
* 'url', 'email', etc.) and returns true if the link should be converted
* into an anchor tag, and false otherwise.
* Accepts a function that takes a discovered link,
* and the link type (e.g., 'url', 'email', etc.),
* and returns true if the link should be converted into an anchor tag,
* and false otherwise.
*
* Accepts an object where each key is the link type and each value is the
* the validation option to use for that type
*
* @default null
*/
validate?: PossiblyByType<PossiblyFuncOfHrefAndType<boolean>>;
validate?: boolean | ((href: string, type: LinkEntityType) => boolean) | Partial<Record<LinkEntityType, ((href: string) => boolean)>> | null;
}
+61
View File
@@ -0,0 +1,61 @@
import * as Linkify from 'linkifyjs';
Linkify.find(); // $ExpectError
Linkify.find(1); // $ExpectError
Linkify.find('my string', 1); // $ExpectError
Linkify.find('my string'); // $ExpectType FindResultHash[]
Linkify.find('my string', 'email'); // $ExpectType FindResultHash[]
Linkify.find('my string', 'hashtag'); // $ExpectType FindResultHash[]
Linkify.find('my string', 'my type'); // $ExpectError
Linkify.test(); // $ExpectError
Linkify.test(1); // $ExpectError
Linkify.test('my string', 1); // $ExpectError
Linkify.test('my string'); // $ExpectType boolean
Linkify.test('my string', 'email'); // $ExpectType boolean
Linkify.test('my string', 'hashtag'); // $ExpectType boolean
Linkify.test('my string', 'my type'); // $ExpectError
Linkify.tokenize(); // $ExpectError
Linkify.tokenize(1); // $ExpectError
Linkify.tokenize('my string'); // $ExpectType { v: { v: string; }[]; }[]
let options: Linkify.Options;
options = {}; // $ExpectType {}
options = { attributes: null }; // $ExpectType { attributes: null; }
options = { attributes: 'hello-world' }; // $ExpectError
options = { attributes: { attr: 'hello-world' } }; // $ExpectType { attributes: { attr: string; }; }
options = { attributes: href => ({}) }; // $ExpectType { attributes: (href: string) => {}; }
options = { className: null }; // $ExpectError
options = { className: 'new-link--url' }; // $ExpectType { className: string; }
options = { className: (href, type) => `new-link-${type}` }; // $ExpectType { className: (href: string, type: LinkEntityType) => string; }
options = { className: { sunshine: v => v } }; // $ExpectError
options = { className: { email: () => 'new-link--email' } }; // $ExpectType { className: { email: () => string; }; }
options = { defaultProtocol: null }; // $ExpectError
options = { defaultProtocol: 1 }; // $ExpectError
options = { defaultProtocol: 'http' }; // $ExpectType { defaultProtocol: string; }
options = { defaultProtocol: 'ftp' }; // $ExpectType { defaultProtocol: string; }
options = { format: null }; // $ExpectType { format: null; }
options = { format: value => value }; // $ExpectType { format: (value: string) => string; }
options = { format: { sunshine: v => v } }; // $ExpectError
options = { format: { email: () => 'sunshine' } }; // $ExpectType { format: { email: () => string; }; }
options = { formatHref: null }; // $ExpectType { formatHref: null; }
options = { formatHref: href => href }; // $ExpectType { formatHref: (href: string) => string; }
options = { formatHref: { sunshine: v => v } }; // $ExpectError
options = { formatHref: { email: () => 'sunshine' } }; // $ExpectType { formatHref: { email: () => string; }; }
options = { nl2br: 1 }; // $ExpectError
options = { nl2br: true }; // $ExpectType { nl2br: true; }
options = { tagName: null }; // $ExpectError
options = { tagName: 'span' }; // $ExpectType { tagName: string; }
options = { target: null }; // $ExpectError
options = { target: '_parent' }; // $ExpectType { target: string; }
options = { validate: null }; // $ExpectType { validate: null; }
-252
View File
@@ -1,252 +0,0 @@
import * as React from "react";
import linkifyHtml from "linkifyjs/html";
import Linkify from "linkifyjs/react";
import linkifyStr from "linkifyjs/string";
import linkifyElement from "linkifyjs/element";
import { LinkifyOptions } from "linkifyjs";
declare function describe(desc: string, f: () => void): void;
describe("linkifyjs/html", () => {
/**
* The following tests were taken directly from the documentation:
* https://soapbox.github.io/linkifyjs/docs/options.html
*/
/* attributes */
linkifyHtml("github.com", {
attributes: {
rel: "nofollow"
}
});
/* className */
linkifyHtml("github.com", {
className: "new-link--url"
});
linkifyHtml("github.com", {
className(href, type) {
return "new-link--" + type;
}
});
linkifyHtml("github.com", {
className: {
url: "new-link--url",
email(href: string) {
return "new-link--email";
}
}
});
/* events */
linkifyHtml("", {
events: {
click(e) {
alert("Link clicked!");
},
mouseover(e) {
alert("Link hovered!");
}
}
});
/* defaultProtocol */
/* format */
linkifyHtml("", {
format(value, type) {
if (type === "url" && value.length > 50) {
value = value.slice(0, 50) + "…";
}
return value;
}
});
linkifyHtml("", {
format: {
url(value) {
return value.length > 50 ? value.slice(0, 50) + "…" : value;
}
}
});
/* formatHref */
linkifyHtml("This site is #rad", {
formatHref(href, type) {
if (type === "hashtag") {
href = "https://twitter.com/hashtag/" + href.substring(1);
}
return href;
}
});
linkifyHtml("Hey @dhh, check out issue #23", {
formatHref: {
mention(href) {
return "https://github.com" + href;
},
ticket(href) {
return (
"https://github.com/SoapBox/linkifyjs/issues/" +
href.substring(1)
);
}
}
});
/* ignoreTags */
linkifyHtml(
// tslint:disable-next-line:prefer-template
'Please ignore <script>var a = {}; a.com = "Hi";</script> \n' +
"but do <span>b.ca</span>",
{
ignoreTags: ["script", "style"]
}
);
/* nl2br */
/* tagName */
linkifyHtml("github.com", {
tagName: "span"
});
linkifyHtml("#swag", {
tagName: {
hashtag: "span"
}
});
/* target */
linkifyHtml("github.com", {
target: "_parent"
});
linkifyHtml("test-email@example.com", {
target: {
url: "_parent",
email: null
}
});
/* validate */
// Don't linkify links that don't begin in a protocol
// e.g., "http://google.com" will be linkified, but "google.com" will not.
linkifyHtml("www.google.com", {
validate: {
url(value) {
return /^(http|ftp)s?:\/\//.test(value);
}
}
});
});
describe("linkifyjs/react", () => {
/**
* The following tests were taken directly from the documentation:
* https://soapbox.github.io/linkifyjs/docs/linkify-react.html
*/
/* Usage */
{
// render()
const options = {
/* … */
};
const content =
"For help with GitHub.com, please email support@github.com";
<Linkify tagName="p" options={options}>
{content}
</Linkify>;
}
/* Events */
{
const content =
"For help with GitHub.com, please email support@github.com";
const linkProps = {
onClick: (event: any) => {
if (!confirm("Are you sure you want to leave this page?")) {
event.preventDefault();
}
}
};
<Linkify options={{ attributes: linkProps }}>{content}</Linkify>;
}
/**
* The following tests were made specifically for DefinitelyTyped.
*/
/* Default values for all props */
{
const content =
"For help with GitHub.com, please email support@github.com";
<Linkify>
<span>{content}</span>
</Linkify>;
}
/* Custom class name */
{
const content =
"For help with GitHub.com, please email support@github.com";
<Linkify
options={{
className: "custom-class-name"
}}
>
<span>{content}</span>
</Linkify>;
}
/* Custom tag name */
{
const content =
"For help with GitHub.com, please email support@github.com";
<Linkify
options={{
tagName: "p"
}}
>
<span>{content}</span>
</Linkify>;
}
});
describe("linkifyjs/string", () => {
/**
* The following tests were based on the documentation:
* https://soapbox.github.io/linkifyjs/docs/linkify-string.html
*/
const options: LinkifyOptions = {};
const str = '<p>For help with GitHub.com, please email support@github.com</p>';
const result1: string = linkifyStr(str, options);
const result2: string = linkifyStr(str);
});
describe("linkifyjs/element", () => {
/**
* The following tests were based on the documentation:
* https://soapbox.github.io/linkifyjs/docs/linkify-element.html
*/
const options: LinkifyOptions = {};
const result1: HTMLElement = linkifyElement(document.body, options, document);
const result2: HTMLElement = linkifyElement(document.body, options);
const result3: HTMLElement = linkifyElement(document.body);
});
+3 -5
View File
@@ -1,11 +1,9 @@
import * as React from "react";
import { LinkifyOptions } from "./index";
import { Options } from "./index";
export interface LinkifyProps {
options?: LinkifyOptions;
options?: Options;
tagName?: string;
}
declare class Linkify extends React.Component<LinkifyProps> {}
export default Linkify;
export default class Linkify extends React.Component<LinkifyProps> {}
+2 -3
View File
@@ -1,4 +1,3 @@
import { LinkifyOptions } from "./index";
import { Options } from './index';
export function linkifyStr(str: string, options?: LinkifyOptions): string;
export default linkifyStr;
export default function linkifyStr(str: string, options?: Options): string;
+15 -11
View File
@@ -1,24 +1,28 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": ["es6", "dom"],
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": ["../"],
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "preserve"
"forceConsistentCasingInFileNames": true
},
"files": [
"element.d.ts",
"html.d.ts",
"index.d.ts",
"linkifyjs-tests.tsx",
"react.d.ts",
"string.d.ts"
"element.d.ts",
"html.d.ts",
"index.d.ts",
"linkifyjs-tests.ts",
"react.d.ts",
"string.d.ts"
]
}