Merge pull request #23383 from makepost/master

Remarkable: Add types
This commit is contained in:
Daniel Rosenwasser
2018-02-13 11:42:49 -08:00
committed by GitHub
8 changed files with 835 additions and 0 deletions

8
types/remarkable/index.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
// Type definitions for remarkable 1.7
// Project: https://github.com/jonschlinkert/remarkable
// Definitions by: makepost <https://github.com/makepost>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
import Remarkable = require("./lib");
export = Remarkable;

15
types/remarkable/lib/common/utils.d.ts vendored Normal file
View File

@@ -0,0 +1,15 @@
export function isString(obj?: any): boolean;
export function has(object: any, key: string): boolean;
export function assign(target: any, ...sources: any[]): any;
export function unescapeMd(str: string): string;
export function isValidEntityCode(c: number): boolean;
export function fromCodePoint(c: number): string;
export function replaceEntities(str: string): string;
export function escapeHtml(str: string): string;

347
types/remarkable/lib/index.d.ts vendored Normal file
View File

@@ -0,0 +1,347 @@
import * as Utils from "./common/utils";
import Renderer = require("./renderer");
import Ruler = require("./ruler");
export = Remarkable;
declare class Remarkable {
/**
* Useful helper functions for custom rendering.
*/
static utils: typeof Utils;
inline: { ruler: Ruler };
block: { ruler: Ruler };
core: { ruler: Ruler };
renderer: Renderer;
/**
* Markdown parser, done right.
*/
constructor(options?: Remarkable.Options);
/**
* Remarkable offers some "presets" as a convenience to quickly enable/disable
* active syntax rules and options for common use cases.
*/
constructor(preset: "commonmark" | "full" | "remarkable", options?: Remarkable.Options);
/**
* `"# Remarkable rulezz!"` => `"<h1>Remarkable rulezz!</h1>"`
*/
render(markdown: string, env?: Remarkable.Env): string;
/**
* Define options.
*
* Note: To achieve the best possible performance, don't modify a Remarkable instance
* on the fly. If you need multiple configurations, create multiple instances and
* initialize each with a configuration that is ideal for that instance.
*/
set(options: Remarkable.Options): void;
/**
* Use a plugin.
*/
use(plugin: Remarkable.Plugin, options?: any): Remarkable;
/**
* Batch loader for components rules states, and options.
*/
configure(presets: Remarkable.Presets): void;
/**
* Parse the input `string` and return a tokens array.
* Modifies `env` with definitions data.
*/
parse(str: string, env: Remarkable.Env): Remarkable.Token[];
/**
* Parse the given content `string` as a single string.
*/
parseInline(str: string, env: Remarkable.Env): Remarkable.Token[];
/**
* Render a single content `string`, without wrapping it
* to paragraphs.
*/
renderInline(str: string, env?: Remarkable.Env): string;
}
declare namespace Remarkable {
interface Env {
[key: string]: any;
}
type GetBreak = (tokens: Token[], idx: number) => "" | "\n";
interface Options {
/**
* Enable HTML tags in source.
*/
html?: boolean;
/**
* Use "/" to close single tags (<br />).
*/
xhtmlOut?: boolean;
/**
* Convert "\n" in paragraphs into <br>.
*/
breaks?: boolean;
/**
* CSS language prefix for fenced blocks.
*/
langPrefix?: string;
/**
* Autoconvert URL-like text to links.
*/
linkify?: boolean;
/**
* Enable some language-neutral replacement + quotes beautification.
*/
typographer?: boolean;
/**
* Double + single quotes replacement pairs, when typographer enabled,
* and smartquotes on. Set doubles to "«»" for Russian, "„“" for German.
*/
quotes?: string;
/**
* Highlighter function. Should return escaped HTML, or "" if the source
* string is not changed.
*/
highlight?(str: string, lang: string): string;
}
type Plugin = (md: Remarkable, options?: any) => void;
interface Presets {
components: {
[name: string]: {
rules: Rules,
},
};
options: Options;
}
type Rule = (
/**
* The list of tokens currently being processed.
*/
tokens: Token[],
/**
* The index of the token currently being processed.
*/
idx: number,
/**
* The options given to remarkable.
*/
options: Options,
/**
* The key-value store created by the parsing rules.
*/
env: Env,
) => string;
interface Rules {
[name: string]: Rule;
"blockquote_open": Rule;
"blockquote_close": Rule;
"code": Rule;
"fence": Rule;
"fence_custom": Rule;
"heading_open": Rule;
"heading_close": Rule;
"hr": Rule;
"bullet_list_open": Rule;
"bullet_list_close": Rule;
"list_item_open": Rule;
"list_item_close": Rule;
"ordered_list_open": Rule;
"ordered_list_close": Rule;
"paragraph_open": Rule;
"paragraph_close": Rule;
"link_open": Rule;
"link_close": Rule;
"image": Rule;
"table_open": Rule;
"table_close": Rule;
"thead_open": Rule;
"thead_close": Rule;
"tbody_open": Rule;
"tbody_close": Rule;
"tr_open": Rule;
"tr_close": Rule;
"th_open": Rule;
"th_close": Rule;
"td_open": Rule;
"td_close": Rule;
"strong_open": Rule;
"strong_close": Rule;
"em_open": Rule;
"em_close": Rule;
"del_open": Rule;
"del_close": Rule;
"ins_open": Rule;
"ins_close": Rule;
"mark_open": Rule;
"mark_close": Rule;
"sub": Rule;
"sup": Rule;
"hardbreak": Rule;
"softbreak": Rule;
"text": Rule;
"htmlblock": Rule;
"htmltag": Rule;
"abbr_open": Rule;
"abbr_close": Rule;
"footnote_ref": Rule;
"footnote_block_open": Rule;
"footnote_block_close": Rule;
"footnote_open": Rule;
"footnote_close": Rule;
"footnote_anchor": Rule;
"dl_open": Rule;
"dt_open": Rule;
"dd_open": Rule;
"dl_close": Rule;
"dt_close": Rule;
"dd_close": Rule;
/**
* Check to see if `\n` is needed before the next token.
*/
getBreak: GetBreak;
}
interface BaseToken {
/**
* The nesting level of the associated markdown structure in the source.
*/
level: number;
/**
* Tokens generated by block parsing rules also include a `lines`
* property which is a 2 elements array marking the first and last line of the
* `src` used to generate the token.
*/
lines?: [number, number];
}
interface TagToken extends BaseToken {
/**
* Tag tokens have a variety of types and each is a name of a
* rendering rule.
*/
type: string;
}
interface ContentToken extends BaseToken {
/**
* A text token has a `content` property containing the text it represents.
*/
content: string;
/**
* The type of the token.
*/
type: "text";
}
interface BlockContentToken extends BaseToken {
/**
* The content of the block. This might include inline mardown syntax
* which may need further processing by the inline rules.
*/
content: string;
/**
* This is initialized with an empty array (`[]`) and will be filled
* with the inline parser tokens as the inline parsing rules are applied.
*/
children: Token[];
/**
* The type of the token.
*/
type: "inline";
}
interface MiscTokenProps {
/**
* Image alt.
*/
alt?: string;
/**
* Code: `true` if block, `false` if inline.
*/
block?: boolean;
/**
* Footnote label.
*/
label?: any;
/**
* Heading level.
*/
hLevel?: number;
/**
* Link url.
*/
href?: string;
/**
* Footnote id.
*/
id?: number;
/**
* Ordered list marker value.
*/
order?: number;
/**
* Fenced block params.
*/
params?: any[];
/**
* Image url.
*/
src?: string;
/**
* Footnote sub id.
*/
subId?: number;
/**
* Absence of empty line before current tag: `true` if absent, `false`
* if present. List is tight if any list item is tight.
*/
tight?: boolean;
/**
* Abbreviation title.
*/
title?: string;
}
type Token = (TagToken | ContentToken | BlockContentToken) & MiscTokenProps;
}

28
types/remarkable/lib/renderer.d.ts vendored Normal file
View File

@@ -0,0 +1,28 @@
import Remarkable = require(".");
export = Renderer;
/**
* Renderer class. Renders HTML and exposes `rules` to allow
* local modifications.
*/
declare class Renderer {
rules: Remarkable.Rules;
/**
* Exported helper, for custom rules only.
*/
getBreak: Remarkable.GetBreak;
/**
* Render a string of inline HTML with the given `tokens` and
* `options`.
*/
renderInline(tokens: Remarkable.Token[], options: Remarkable.Options, env: Remarkable.Env): string;
/**
* Render a string of HTML with the given `tokens` and
* `options`.
*/
render(tokens: Remarkable.Token[], options: Remarkable.Options, env: Remarkable.Env): string;
}

52
types/remarkable/lib/ruler.d.ts vendored Normal file
View File

@@ -0,0 +1,52 @@
import Remarkable = require(".");
export = Ruler;
/**
* Ruler is a helper class for building responsibility chains from
* parse rules. It allows:
*
* - easy stack rules chains
* - getting main chain and named chains content (as arrays of functions)
*/
declare class Ruler {
/**
* Replace the rule `ruleName` with a new rule.
*/
at(ruleName: string, fn: Remarkable.Rule, options: Remarkable.Options): void;
/**
* Add a rule to the chain before given the `ruleName`.
*/
before(beforeName: string, ruleName: string, fn: Remarkable.Rule, options: Remarkable.Options): void;
/**
* Add a rule to the chain after the given `ruleName`.
*/
after(afterName: string, ruleName: string, fn: Remarkable.Rule, options: Remarkable.Options): void;
/**
* Add a rule to the end of chain.
*/
push(ruleName: string, fn: Remarkable.Rule, options: Remarkable.Options): void;
/**
* Enable a rule or list of rules.
*
* @param list Name or array of rule names to enable.
* @param strict If `true`, all non listed rules will be disabled.
*/
enable(list: string | string[], strict?: boolean): void;
/**
* Disable a rule or list of rules.
*
* @param list Name or array of rule names to disable.
*/
disable(list: string | string[]): void;
/**
* Get a rules list as an array of functions.
*/
getRules(chainName: string): Remarkable.Rule[];
}

View File

@@ -0,0 +1,355 @@
// This code does not run, but it is type-checked.
import hljs = require("highlight.js");
import Remarkable = require("remarkable");
/**
* Examples from README.
*/
export class RemarkableTest {
usage() {
const md = new Remarkable();
md.render("# Remarkable rulezz!");
}
defineOptionsInContructor() {
const md = new Remarkable({
html: false,
xhtmlOut: false,
breaks: false,
langPrefix: "language-",
linkify: false,
typographer: false,
quotes: "“”‘’",
highlight(/*str, lang*/) { return ""; },
});
md.render("# Remarkable rulezz!");
}
defineOptions() {
const md = new Remarkable();
md.set({
html: true,
breaks: true,
});
}
enableStrict() {
const md = new Remarkable("commonmark");
md.render("# Remarkable rulezz!");
}
enableAllRules() {
let md = new Remarkable("full");
// Or with options:
md = new Remarkable("full", {
html: true,
linkify: true,
typographer: true,
});
md.render("# Remarkable rulezz!");
}
highlightFencedCodeBlocks() {
const md = new Remarkable({
highlight(str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) { }
}
try {
return hljs.highlightAuto(str).value;
} catch (err) { }
return "";
},
});
md.render("# Remarkable rulezz!");
}
manageRules() {
let md = new Remarkable();
md.inline.ruler.enable(["ins", "mark"]);
md.block.ruler.disable(["table", "footnote"]);
// Enable everything
md = new Remarkable("full", {
html: true,
linkify: true,
typographer: true,
});
}
enableRulesManually() {
const md = new Remarkable();
md.core.ruler.enable([
"abbr",
]);
md.block.ruler.enable([
"footnote",
"deflist",
]);
md.inline.ruler.enable([
"footnote_inline",
"ins",
"mark",
"sub",
"sup",
]);
}
typographer() {
const md = new Remarkable({
typographer: true,
quotes: "“”‘’",
});
// Disable rules at all:
md.core.ruler.disable(["replacements", "smartquotes"]);
}
loadPlugins() {
const md = new Remarkable();
const noop = () => { };
const plugin1: Remarkable.Plugin = noop as (md: Remarkable) => void;
const plugin2: Remarkable.Plugin = noop as (md: Remarkable, options: {}) => void;
const plugin3: Remarkable.Plugin = noop as (md: Remarkable) => void;
const opts: any = undefined;
md.use(plugin1)
.use(plugin2, opts)
.use(plugin3);
}
touchParserAndRenderer() {
const md = new Remarkable();
md.core;
md.core.ruler;
md.block;
md.block.ruler;
md.inline;
md.inline.ruler;
md.renderer;
md.renderer.rules;
}
}
/**
* Various tokens copied from source.
*/
export class TokenTest {
blockRules() {
const tokens: Remarkable.Token[] = [];
const state = {
level: 0,
line: 0,
tokens,
};
const lines: [number, number] = [0, 0];
const startLine = 0;
state.tokens.push({
type: "blockquote_open",
lines,
level: state.level++,
});
state.tokens.push({
type: "blockquote_close",
level: --state.level,
});
state.tokens.push({
type: "code",
content: "",
block: true,
lines,
level: state.level,
});
state.tokens.push({
type: "inline",
content: "",
level: state.level + 1,
lines,
children: [],
});
state.tokens.push({
type: "fence",
params: [],
content: "",
lines: [startLine, state.line],
level: state.level,
});
state.tokens.push({
type: "footnote_reference_open",
label: "",
level: state.level++,
});
state.tokens.push({ type: "heading_close", hLevel: 1, level: state.level });
state.tokens.push({
type: "ordered_list_open",
order: 0,
lines: [startLine, 0],
level: state.level++,
});
state.tokens.push({
type: "paragraph_open",
tight: false,
lines: [startLine, state.line],
level: state.level,
});
}
coreRules() {
const env: Remarkable.Env = {};
const nodes: Remarkable.Token[] = [];
const tokens = nodes;
const state = { env, src: "", tokens };
const m = ["", "", ""];
let level = 0;
nodes.push({
type: "text",
content: "",
level,
});
nodes.push({
type: "abbr_open",
title: state.env["abbreviations"][":" + m[2]],
level: level++,
});
nodes.push({
type: "text",
content: m[2],
level,
});
nodes.push({
type: "abbr_close",
level: --level,
});
state.tokens.push({
type: "inline",
content: state.src.replace(/\n/g, " ").trim(),
level: 0,
lines: [0, 1],
children: [],
});
tokens.push({
type: "inline",
content: "",
level,
children: [],
});
}
inlineRules() {
const state: Remarkable.Token[] = [];
let level = 0;
state.push({
type: "link_open",
href: "",
level,
});
state.push({
type: "code",
content: "",
block: false,
level,
});
state.push({
type: "footnote_ref",
id: 1,
level,
});
state.push({
type: "footnote_ref",
id: 1,
subId: 1,
level,
});
state.push({
type: "image",
src: "",
title: "",
alt: "",
level,
});
state.push({
type: "link_open",
href: "",
title: "",
level: level++,
});
}
}
/**
* Helper function usage.
*/
export class UtilsTest {
isString() {
Remarkable.utils.isString("foo");
Remarkable.utils.isString(1);
Remarkable.utils.isString({});
Remarkable.utils.isString();
}
has() {
Remarkable.utils.has({ foo: "bar" }, "foo");
Remarkable.utils.has({}, "foo");
}
assign() {
Remarkable.utils.assign({}, { foo: "bar" }, { baz: "qux" });
}
unescapeMd() {
Remarkable.utils.unescapeMd("\\<foo /\\>");
}
isValidEntityCode() {
Remarkable.utils.isValidEntityCode(0xD800);
Remarkable.utils.isValidEntityCode(0xD7FF);
Remarkable.utils.isValidEntityCode(1000);
}
fromCodePoint() {
Remarkable.utils.fromCodePoint(0xffff + 1);
Remarkable.utils.fromCodePoint(0xffff);
}
replaceEntities() {
Remarkable.utils.replaceEntities("");
Remarkable.utils.replaceEntities("&nbsp;");
}
escapeHtml() {
Remarkable.utils.replaceEntities('<script>alert("&copy;")</script>');
}
}

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"lib/common/utils.d.ts",
"lib/index.d.ts",
"lib/renderer.d.ts",
"lib/ruler.d.ts",
"index.d.ts",
"remarkable-tests.ts"
]
}

View File

@@ -0,0 +1,3 @@
{
"extends": "dtslint/dt.json"
}