From abf12473cf09a01658c91f6c00ff69fb87285fec Mon Sep 17 00:00:00 2001 From: duduluu Date: Sat, 11 Apr 2020 02:39:40 +0800 Subject: [PATCH] [markdown-it] Update types for markdown-it v10.0.0 (#42860) * [markdown-it] Upgrade for v10.0.0 * [markdown-it]: rollback ts version to 2.0 and complete tests * [prosemirror-markdown]: fix test due to markdown-it types update --- types/markdown-it/index.d.ts | 11 +- types/markdown-it/lib/common/entities.d.ts | 7 + types/markdown-it/lib/common/html_blocks.d.ts | 3 + types/markdown-it/lib/common/html_re.d.ts | 8 + types/markdown-it/lib/common/utils.d.ts | 70 +++ types/markdown-it/lib/helpers/index.d.ts | 13 + .../lib/helpers/parse_link_destination.d.ts | 12 + .../lib/helpers/parse_link_label.d.ts | 5 + .../lib/helpers/parse_link_title.d.ts | 5 + types/markdown-it/lib/index.d.ts | 479 ++++++++++++++---- types/markdown-it/lib/parser_block.d.ts | 30 +- types/markdown-it/lib/parser_core.d.ts | 29 +- types/markdown-it/lib/parser_inline.d.ts | 47 +- types/markdown-it/lib/renderer.d.ts | 98 +++- types/markdown-it/lib/ruler.d.ts | 180 ++++++- .../lib/rules_block/state_block.d.ts | 153 +++++- .../lib/rules_core/state_core.d.ts | 27 +- .../lib/rules_inline/state_inline.d.ts | 92 ++-- types/markdown-it/lib/token.d.ts | 132 ++++- types/markdown-it/markdown-it-tests.ts | 184 +++---- types/markdown-it/test/common/utils.ts | 42 ++ types/markdown-it/test/helpers/index.ts | 8 + types/markdown-it/test/index.ts | 137 +++++ types/markdown-it/test/parser_block.ts | 16 + types/markdown-it/test/parser_core.ts | 14 + types/markdown-it/test/parser_inline.ts | 20 + types/markdown-it/test/renderer.ts | 68 +++ types/markdown-it/test/ruler.ts | 36 ++ .../test/rules_block/state_block.ts | 61 +++ .../markdown-it/test/rules_core/state_core.ts | 21 + .../test/rules_inline/state_inline.ts | 54 ++ types/markdown-it/test/token.ts | 23 + types/markdown-it/tsconfig.json | 13 + types/markdown-it/tslint.json | 2 +- .../prosemirror-markdown-tests.ts | 2 +- 35 files changed, 1760 insertions(+), 342 deletions(-) create mode 100644 types/markdown-it/lib/common/entities.d.ts create mode 100644 types/markdown-it/lib/common/html_blocks.d.ts create mode 100644 types/markdown-it/lib/common/html_re.d.ts create mode 100644 types/markdown-it/lib/common/utils.d.ts create mode 100644 types/markdown-it/lib/helpers/index.d.ts create mode 100644 types/markdown-it/lib/helpers/parse_link_destination.d.ts create mode 100644 types/markdown-it/lib/helpers/parse_link_label.d.ts create mode 100644 types/markdown-it/lib/helpers/parse_link_title.d.ts create mode 100644 types/markdown-it/test/common/utils.ts create mode 100644 types/markdown-it/test/helpers/index.ts create mode 100644 types/markdown-it/test/index.ts create mode 100644 types/markdown-it/test/parser_block.ts create mode 100644 types/markdown-it/test/parser_core.ts create mode 100644 types/markdown-it/test/parser_inline.ts create mode 100644 types/markdown-it/test/renderer.ts create mode 100644 types/markdown-it/test/ruler.ts create mode 100644 types/markdown-it/test/rules_block/state_block.ts create mode 100644 types/markdown-it/test/rules_core/state_core.ts create mode 100644 types/markdown-it/test/rules_inline/state_inline.ts create mode 100644 types/markdown-it/test/token.ts diff --git a/types/markdown-it/index.d.ts b/types/markdown-it/index.d.ts index e7d0ffa6e7..38b205a785 100644 --- a/types/markdown-it/index.d.ts +++ b/types/markdown-it/index.d.ts @@ -1,8 +1,11 @@ -// Type definitions for markdown-it +// Type definitions for markdown-it v10.0.0 // Project: https://github.com/markdown-it/markdown-it -// Definitions by: York Yao , Robert Coie +// Definitions by: York Yao +// Robert Coie +// duduluu // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.0 + +import MarkdownIt = require('./lib'); -import MarkdownIt = require("./lib"); export = MarkdownIt; diff --git a/types/markdown-it/lib/common/entities.d.ts b/types/markdown-it/lib/common/entities.d.ts new file mode 100644 index 0000000000..dfa7380f44 --- /dev/null +++ b/types/markdown-it/lib/common/entities.d.ts @@ -0,0 +1,7 @@ +interface MapType { + [key: string]: string; +} + +declare const entities: MapType; + +export = entities; diff --git a/types/markdown-it/lib/common/html_blocks.d.ts b/types/markdown-it/lib/common/html_blocks.d.ts new file mode 100644 index 0000000000..08e5290c55 --- /dev/null +++ b/types/markdown-it/lib/common/html_blocks.d.ts @@ -0,0 +1,3 @@ +declare const htmlBlocks: string[]; + +export = htmlBlocks; diff --git a/types/markdown-it/lib/common/html_re.d.ts b/types/markdown-it/lib/common/html_re.d.ts new file mode 100644 index 0000000000..6ff85e6b58 --- /dev/null +++ b/types/markdown-it/lib/common/html_re.d.ts @@ -0,0 +1,8 @@ +interface HtmlRE { + HTML_TAG_RE: RegExp; + HTML_OPEN_CLOSE_TAG_RE: RegExp; +} + +declare const htmlRE: HtmlRE; + +export = htmlRE; diff --git a/types/markdown-it/lib/common/utils.d.ts b/types/markdown-it/lib/common/utils.d.ts new file mode 100644 index 0000000000..9c2ff2096c --- /dev/null +++ b/types/markdown-it/lib/common/utils.d.ts @@ -0,0 +1,70 @@ +import * as mdurl from 'mdurl'; +// import ucmicro from 'uc.micro'; + +interface Utils { + lib: { + mdurl: typeof mdurl; + }; + + /** + * Merge objects + */ + assign(target: any, ...sources: any[]): any; + + /** + * Check if the type is string or not + */ + isString(obj: any): obj is string; + + /** + * has own property + */ + has(obj: any, key: keyof any): boolean; + + unescapeMd(str: string): string; + unescapeAll(str: string): string; + + isValidEntityCode(code: number): boolean; + fromCodePoint(code: number): string; + escapeHtml(str: string): string; + + /** + * Remove element from array and put another array at those position. + * Useful for some operations with tokens. + * Return a new array. + */ + arrayReplaceAt(src: T[], pos: number, newElements: T[]): T[]; + + isSpace(code: number): boolean; + + /** + * Zs (unicode class) || [\t\f\v\r\n] + */ + isWhiteSpace(code: number): boolean; + + /** + * Markdown ASCII punctuation characters. + * + * !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~ + * http://spec.commonmark.org/0.15/#ascii-punctuation-character + * + * Don't confuse with unicode punctuation !!! It lacks some chars in ascii range. + */ + isMdAsciiPunct(code: number): boolean; + + /** + * Currently without astral characters support. + */ + isPunctChar(ch: string): boolean; + + escapeRE(str: string): string; + + /** + * Hepler to unify [reference labels]. + */ + normalizeReference(str: string): string; +} + +declare const utils: Utils; + +export = utils; diff --git a/types/markdown-it/lib/helpers/index.d.ts b/types/markdown-it/lib/helpers/index.d.ts new file mode 100644 index 0000000000..a32643c5ae --- /dev/null +++ b/types/markdown-it/lib/helpers/index.d.ts @@ -0,0 +1,13 @@ +import parseLinkLabel = require('./parse_link_label'); +import parseLinkDestination = require('./parse_link_destination'); +import parseLinkTitle = require('./parse_link_title'); + +interface Helpers { + parseLinkLabel: typeof parseLinkLabel; + parseLinkDestination: typeof parseLinkDestination; + parseLinkTitle: typeof parseLinkTitle; +} + +declare const helpers: Helpers; + +export = helpers; diff --git a/types/markdown-it/lib/helpers/parse_link_destination.d.ts b/types/markdown-it/lib/helpers/parse_link_destination.d.ts new file mode 100644 index 0000000000..b0f78aab40 --- /dev/null +++ b/types/markdown-it/lib/helpers/parse_link_destination.d.ts @@ -0,0 +1,12 @@ +declare namespace parseLinkDestination { + interface ParseResult { + ok: boolean; + pos: number; + lines: number; + str: string; + } +} + +declare function parseLinkDestination(str: string, pos: number, max: number): parseLinkDestination.ParseResult; + +export = parseLinkDestination; diff --git a/types/markdown-it/lib/helpers/parse_link_label.d.ts b/types/markdown-it/lib/helpers/parse_link_label.d.ts new file mode 100644 index 0000000000..fe13c48bd4 --- /dev/null +++ b/types/markdown-it/lib/helpers/parse_link_label.d.ts @@ -0,0 +1,5 @@ +import State = require('../rules_core/state_core'); + +declare function parseLinkLabel(state: State, start: number, disableNested?: boolean): number; + +export = parseLinkLabel; diff --git a/types/markdown-it/lib/helpers/parse_link_title.d.ts b/types/markdown-it/lib/helpers/parse_link_title.d.ts new file mode 100644 index 0000000000..f327d838aa --- /dev/null +++ b/types/markdown-it/lib/helpers/parse_link_title.d.ts @@ -0,0 +1,5 @@ +import Destination = require('./parse_link_destination'); + +declare function parseLinkTitle(str: string, pos: number, max: number): Destination.ParseResult; + +export = parseLinkTitle; diff --git a/types/markdown-it/lib/index.d.ts b/types/markdown-it/lib/index.d.ts index b516a241fc..fda1d24868 100644 --- a/types/markdown-it/lib/index.d.ts +++ b/types/markdown-it/lib/index.d.ts @@ -1,113 +1,410 @@ -import { LinkifyIt } from 'linkify-it' - +import utils = require('./common/utils'); +import helpers = require('./helpers'); import State = require('./rules_core/state_core'); -import StateBlock = require('./rules_block/state_block'); -import StateInline = require('./rules_inline/state_inline'); - -import Core = require('./parser_core'); +import Renderer = require('./renderer'); +import ParserCore = require('./parser_core'); import ParserBlock = require('./parser_block'); import ParserInline = require('./parser_inline'); -import Renderer = require('./renderer'); -import Ruler = require('./ruler'); +import LinkifyIt = require('linkify-it'); +import mdurl = require('mdurl'); +import punycode = require('punycode'); + import Token = require('./token'); -export = MarkdownIt; -export as namespace markdownit; +declare namespace MarkdownIt { + /** + * MarkdownIt provides named presets as a convenience to quickly + * enable/disable active syntax rules and options for common use cases. + * + * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.js) - + * configures parser to strict [CommonMark](http://commonmark.org/) mode. + * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) - + * similar to GFM, used when no preset name given. Enables all available rules, + * but still without html, typographer & autolinker. + * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) - + * all rules disabled. Useful to quickly setup your config via `.enable()`. + * For example, when you need only `bold` and `italic` markup and nothing else. + */ + type PresetName = 'default' | 'zero' | 'commonmark'; -declare const MarkdownIt: MarkdownItConstructor; + interface Options { + /** + * Set `true` to enable HTML tags in source. Be careful! + * That's not safe! You may need external sanitizer to protect output from XSS. + * It's better to extend features via plugins, instead of enabling HTML. + * @default false + */ + html?: boolean; + + /** + * Set `true` to add '/' when closing single tags + * (`
`). This is needed only for full CommonMark compatibility. In real + * world you will need HTML output. + * @default false + */ + xhtmlOut?: boolean; + + /** + * Set `true` to convert `\n` in paragraphs into `
`. + * @default false + */ + breaks?: boolean; + + /** + * CSS language class prefix for fenced blocks. + * Can be useful for external highlighters. + * @default 'language-' + */ + langPrefix?: string; + + /** + * Set `true` to autoconvert URL-like text to links. + * @default false + */ + linkify?: boolean; + + /** + * Set `true` to enable [some language-neutral replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.js) + + * quotes beautification (smartquotes). + * @default false + */ + typographer?: boolean; + + /** + * Double + single quotes replacement + * pairs, when typographer enabled and smartquotes on. For example, you can + * use `'«»„“'` for Russian, `'„“‚‘'` for German, and + * `['«\xA0', '\xA0»', '‹\xA0', '\xA0›']` for French (including nbsp). + * @default '“”‘’' + */ + quotes?: string | string[]; + + /** + * Highlighter function for fenced code blocks. + * Highlighter `function (str, lang)` should return escaped HTML. It can also + * return empty string if the source was not changed and should be escaped + * externaly. If result starts with string) | null; + } + + type PluginSimple = (md: MarkdownIt) => void; + type PluginWithOptions = (md: MarkdownIt, options?: T) => void; + type PluginWithParams = (md: MarkdownIt, ...params: any[]) => void; +} interface MarkdownItConstructor { new (): MarkdownIt; - new (presetName: "commonmark" | "zero" | "default", options?: MarkdownIt.Options): MarkdownIt; + new (presetName: MarkdownIt.PresetName, options?: MarkdownIt.Options): MarkdownIt; new (options: MarkdownIt.Options): MarkdownIt; (): MarkdownIt; - (presetName: "commonmark" | "zero" | "default", options ?: MarkdownIt.Options): MarkdownIt; + (presetName: MarkdownIt.PresetName, options?: MarkdownIt.Options): MarkdownIt; (options: MarkdownIt.Options): MarkdownIt; } interface MarkdownIt { - render(md: string, env?: any): string; - renderInline(md: string, env?: any): string; + /** + * Instance of [[ParserInline]]. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + */ + readonly inline: ParserInline; + + /** + * Instance of [[ParserBlock]]. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + */ + readonly block: ParserBlock; + + /** + * Instance of [[Core]] chain executor. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + */ + readonly core: ParserCore; + + /** + * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering + * rules for new token types, generated by plugins. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * function myToken(tokens, idx, options, env, self) { + * //... + * return result; + * }; + * + * md.renderer.rules['my_token'] = myToken + * ``` + * + * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js). + */ + readonly renderer: Renderer; + + /** + * [linkify-it](https://github.com/markdown-it/linkify-it) instance. + * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.js) + * rule. + */ + readonly linkify: LinkifyIt.LinkifyIt; + + /** + * Link validation function. CommonMark allows too much in links. By default + * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas + * except some embedded image types. + * + * You can change this behaviour: + * + * ```javascript + * var md = require('markdown-it')(); + * // enable everything + * md.validateLink = function () { return true; } + * ``` + */ + validateLink(url: string): boolean; + + /** + * Function used to encode link url to a machine-readable format, + * which includes url-encoding, punycode, etc. + */ + normalizeLink(url: string): string; + + /** + * Function used to decode link url to a human-readable format` + */ + normalizeLinkText(url: string): string; + + readonly utils: typeof utils; + + readonly helpers: typeof helpers; + + readonly options: MarkdownIt.Options; + + /** + * *chainable* + * + * Set parser options (in the same format as in constructor). Probably, you + * will never need it, but you can change options after constructor call. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .set({ html: true, breaks: true }) + * .set({ typographer: true }); + * ``` + * + * __Note:__ To achieve the best possible performance, don't modify a + * `markdown-it` instance options on the fly. If you need multiple configurations + * it's best to create multiple instances and initialize each with separate + * config. + */ + set(options: MarkdownIt.Options): this; + + /** + * *chainable*, *internal* + * + * Batch load of all options and compenent settings. This is internal method, + * and you probably will not need it. But if you with - see available presets + * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets) + * + * We strongly recommend to use presets instead of direct config loads. That + * will give better compatibility with next versions. + */ + configure(presets: MarkdownIt.PresetName): this; + + /** + * *chainable* + * + * Enable list or rules. It will automatically find appropriate components, + * containing rules with given names. If rule not found, and `ignoreInvalid` + * not set - throws exception. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .enable(['sub', 'sup']) + * .disable('smartquotes'); + * ``` + * + * @param list rule name or list of rule names to enable + * @param ignoreInvalid set `true` to ignore errors when rule not found. + */ + enable(list: string | string[], ignoreInvalid?: boolean): this; + + /** + * *chainable* + * + * The same as [[MarkdownIt.enable]], but turn specified rules off. + * + * @param list rule name or list of rule names to disable. + * @param ignoreInvalid set `true` to ignore errors when rule not found. + */ + disable(list: string | string[], ignoreInvalid?: boolean): this; + + /** + * *chainable* + * + * Load specified plugin with given params into current parser instance. + * It's just a sugar to call `plugin(md, params)` with curring. + * + * ##### Example + * + * ```javascript + * var iterator = require('markdown-it-for-inline'); + * var md = require('markdown-it')() + * .use(iterator, 'foo_replace', 'text', function (tokens, idx) { + * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar'); + * }); + * ``` + */ + use(plugin: MarkdownIt.PluginSimple): this; + use(plugin: MarkdownIt.PluginWithOptions, options?: T): this; + use(plugin: MarkdownIt.PluginWithParams, ...params: any[]): this; + + /** + * *internal* + * + * Parse input string and returns list of block tokens (special token type + * "inline" will contain list of inline tokens). You should not call this + * method directly, until you write custom renderer (for example, to produce + * AST). + * + * `env` is used to pass data between "distributed" rules and return additional + * metadata like reference info, needed for the renderer. It also can be used to + * inject data in specific cases. Usually, you will be ok to pass `{}`, + * and then pass updated object to renderer. + * + * @param src source string + * @param env environment sandbox + */ parse(src: string, env: any): Token[]; + + /** + * Render markdown string into html. It does all magic for you :). + * + * `env` can be used to inject additional metadata (`{}` by default). + * But you will not need it with high probability. See also comment + * in [[MarkdownIt.parse]]. + * + * @param src source string + * @param env environment sandbox + */ + render(src: string, env?: any): string; + + /** + * *internal* + * + * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the + * block tokens list with the single `inline` element, containing parsed inline + * tokens in `children` property. Also updates `env` object. + * + * @param src source string + * @param env environment sandbox + */ parseInline(src: string, env: any): Token[]; - /* - // The following only works in 3.0 - // Since it's still not allowed to target 3.0, i'll leave the code commented out - - use = any[]>( - plugin: (md: MarkdownIt, ...params: T) => void, - ...params: T - ): MarkdownIt; - */ - - use(plugin: (md: MarkdownIt, ...params: any[]) => void, ...params: any[]): MarkdownIt; - - utils: { - assign(obj: any): any; - isString(obj: any): boolean; - has(object: any, key: string): boolean; - unescapeMd(str: string): string; - unescapeAll(str: string): string; - isValidEntityCode(str: any): boolean; - fromCodePoint(str: string): string; - escapeHtml(str: string): string; - arrayReplaceAt(src: any[], pos: number, newElements: any[]): any[] - isSpace(str: any): boolean; - isWhiteSpace(str: any): boolean - isMdAsciiPunct(str: any): boolean; - isPunctChar(str: any): boolean; - escapeRE(str: string): string; - normalizeReference(str: string): string; - } - - disable(rules: string[] | string, ignoreInvalid?: boolean): MarkdownIt; - enable(rules: string[] | string, ignoreInvalid?: boolean): MarkdownIt; - set(options: MarkdownIt.Options): MarkdownIt; - normalizeLink(url: string): string; - normalizeLinkText(url: string): string; - validateLink(url: string): boolean; - block: ParserBlock; - core: Core; - helpers: any; - inline: ParserInline; - linkify: LinkifyIt; - renderer: Renderer; + /** + * Similar to [[MarkdownIt.render]] but for single paragraph content. Result + * will NOT be wrapped into `

` tags. + * + * @param src source string + * @param env environment sandbox + */ + renderInline(src: string, env?: any): string; } -declare module MarkdownIt { - interface Options { - html?: boolean; - xhtmlOut?: boolean; - breaks?: boolean; - langPrefix?: string; - linkify?: boolean; - typographer?: boolean; - quotes?: string; - highlight?: (str: string, lang: string) => void; - } +/** + * Main parser/renderer class. + * + * ##### Usage + * + * ```javascript + * // node.js, "classic" way: + * var MarkdownIt = require('markdown-it'), + * md = new MarkdownIt(); + * var result = md.render('# markdown-it rulezz!'); + * + * // node.js, the same, but with sugar: + * var md = require('markdown-it')(); + * var result = md.render('# markdown-it rulezz!'); + * + * // browser without AMD, added to "window" on script load + * // Note, there are no dash. + * var md = window.markdownit(); + * var result = md.render('# markdown-it rulezz!'); + * ``` + * + * Single line rendering, without paragraph wrap: + * + * ```javascript + * var md = require('markdown-it')(); + * var result = md.renderInline('__markdown-it__ rulezz!'); + * ``` + * + * ##### Example + * + * ```javascript + * // commonmark mode + * var md = require('markdown-it')('commonmark'); + * + * // default mode + * var md = require('markdown-it')(); + * + * // enable everything + * var md = require('markdown-it')({ + * html: true, + * linkify: true, + * typographer: true + * }); + * ``` + * + * ##### Syntax highlighting + * + * ```js + * var hljs = require('highlight.js') // https://highlightjs.org/ + * + * var md = require('markdown-it')({ + * highlight: function (str, lang) { + * if (lang && hljs.getLanguage(lang)) { + * try { + * return hljs.highlight(lang, str, true).value; + * } catch (__) {} + * } + * + * return ''; // use external default escaping + * } + * }); + * ``` + * + * Or with full wrapper override (if you need assign class to `

`):
+ *
+ * ```javascript
+ * var hljs = require('highlight.js') // https://highlightjs.org/
+ *
+ * // Actual default values
+ * var md = require('markdown-it')({
+ *   highlight: function (str, lang) {
+ *     if (lang && hljs.getLanguage(lang)) {
+ *       try {
+ *         return '
' +
+ *                hljs.highlight(lang, str, true).value +
+ *                '
'; + * } catch (__) {} + * } + * + * return '
' + md.utils.escapeHtml(str) + '
'; + * } + * }); + * ``` + */ +declare const MarkdownIt: MarkdownItConstructor; - interface Rule { - (state: S, silent?: boolean): boolean | void; - } - - interface RuleInline extends Rule {} - interface RuleBlock extends Rule {} - - interface RulerInline extends Ruler {} - interface RulerBlock extends Ruler {} - - type TokenRender = (tokens: Token[], index: number, options: any, env: any, self: Renderer) => string; - - interface Delimiter { - close: boolean; - end: number; - jump: number; - length: number; - level: number; - marker: number; - open: boolean; - token: number; - } -} +export = MarkdownIt; diff --git a/types/markdown-it/lib/parser_block.d.ts b/types/markdown-it/lib/parser_block.d.ts index 2efc76b858..c9cfbfc686 100644 --- a/types/markdown-it/lib/parser_block.d.ts +++ b/types/markdown-it/lib/parser_block.d.ts @@ -1,9 +1,29 @@ -import MarkdownIt = require("."); -import Token = require("./token"); +import MarkdownIt = require('.'); +import Ruler = require('./ruler'); +import Token = require('./token'); +import StateBlock = require('./rules_block/state_block'); -export = ParserBlock; +declare namespace ParserBlock { + type RuleBlock = (state: StateBlock, startLine: number, endLine: number, silent: boolean) => boolean; +} declare class ParserBlock { - parse(src: string, md: MarkdownIt, env: any, outTokens: Token[]): void; - ruler: MarkdownIt.RulerBlock; + /** + * [[Ruler]] instance. Keep configuration of block rules. + */ + ruler: Ruler; + + /** + * Generate tokens for input range + */ + tokenize(state: StateBlock, startLine: number, endLine: number): void; + + /** + * Process input string and push block tokens into `outTokens` + */ + parse(str: string, md: MarkdownIt, env: any, outTokens: Token[]): void; + + State: typeof StateBlock; } + +export = ParserBlock; diff --git a/types/markdown-it/lib/parser_core.d.ts b/types/markdown-it/lib/parser_core.d.ts index 67e0cb09bd..6b232d8081 100644 --- a/types/markdown-it/lib/parser_core.d.ts +++ b/types/markdown-it/lib/parser_core.d.ts @@ -1,12 +1,21 @@ -import MarkdownIt = require("."); -import Ruler = require("./ruler"); -import Token = require("./token"); -import StateCore = require("./rules_core/state_core"); +import MarkdownIt = require('.'); +import Ruler = require('./ruler'); +import Token = require('./token'); +import StateCore = require('./rules_core/state_core'); -export = ParserCore; - -declare class ParserCore { - process(state: any): void; - ruler: Ruler; - State: StateCore +declare namespace Core { + type RuleCore = (state: StateCore) => boolean; } + +declare class Core { + ruler: Ruler; + + /** + * Executes core chain rules. + */ + process(state: StateCore): void; + + State: typeof StateCore; +} + +export = Core; diff --git a/types/markdown-it/lib/parser_inline.d.ts b/types/markdown-it/lib/parser_inline.d.ts index ad7aa26d93..7ccf7dc632 100644 --- a/types/markdown-it/lib/parser_inline.d.ts +++ b/types/markdown-it/lib/parser_inline.d.ts @@ -1,13 +1,42 @@ -import MarkdownIt = require("."); -import State = require("./rules_core/state_core"); -import Token = require("./token"); +import MarkdownIt = require('.'); +import Ruler = require('./ruler'); +import Token = require('./token'); +import StateInline = require('./rules_inline/state_inline'); -export = ParserInline; +declare namespace ParserInline { + type RuleInline = (state: StateInline, silent: boolean) => boolean; + type RuleInline2 = (state: StateInline) => boolean; +} declare class ParserInline { - parse(src: string, md: MarkdownIt, env: any, outTokens: Token[]): void; - tokenize(state: State): void; - skipToken(state: State): void; - ruler: MarkdownIt.RulerInline; - ruler2: MarkdownIt.RulerInline; + /** + * [[Ruler]] instance. Keep configuration of inline rules. + */ + ruler: Ruler; + + /** + * [[Ruler]] instance. Second ruler used for post-processing + * (e.g. in emphasis-like rules). + */ + ruler2: Ruler; + + /** + * Skip single token by running all rules in validation mode; + * returns `true` if any rule reported success + */ + skipToken(state: StateInline): void; + + /** + * Generate tokens for input range + */ + tokenize(state: StateInline): void; + + /** + * Process input string and push inline tokens into `outTokens` + */ + parse(str: string, md: MarkdownIt, env: any, outTokens: Token[]): void; + + State: typeof StateInline; } + +export = ParserInline; diff --git a/types/markdown-it/lib/renderer.d.ts b/types/markdown-it/lib/renderer.d.ts index 0231dad0f9..83243bbcff 100644 --- a/types/markdown-it/lib/renderer.d.ts +++ b/types/markdown-it/lib/renderer.d.ts @@ -1,12 +1,96 @@ -import MarkdownIt = require("."); -import Token = require("./token"); +import MarkdownIt = require('.'); +import Token = require('./token'); -export = Renderer; +declare namespace Renderer { + type RenderRule = (tokens: Token[], idx: number, options: MarkdownIt.Options, env: any, self: Renderer) => string; + + interface RenderRuleRecord { + [type: string]: RenderRule | undefined; + code_inline?: RenderRule; + code_block?: RenderRule; + fence?: RenderRule; + image?: RenderRule; + hardbreak?: RenderRule; + softbreak?: RenderRule; + text?: RenderRule; + html_block?: RenderRule; + html_inline?: RenderRule; + } +} declare class Renderer { - rules: { [name: string]: MarkdownIt.TokenRender }; - render(tokens: Token[], options: any, env: any): string; + /** + * Contains render rules for tokens. Can be updated and extended. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.renderer.rules.strong_open = function () { return ''; }; + * md.renderer.rules.strong_close = function () { return ''; }; + * + * var result = md.renderInline(...); + * ``` + * + * Each rule is called as independent static function with fixed signature: + * + * ```javascript + * function my_token_render(tokens, idx, options, env, renderer) { + * // ... + * return renderedHTML; + * } + * ``` + * + * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js) + * for more details and examples. + */ + rules: Renderer.RenderRuleRecord; + + /** + * Render token attributes to string. + */ renderAttrs(token: Token): string; - renderInline(tokens: Token[], options: any, env: any): string; - renderToken(tokens: Token[], idx: number, options: any): string; + + /** + * Default token renderer. Can be overriden by custom function + * in [[Renderer#rules]]. + * + * @param tokens list of tokens + * @param idx token index to render + * @param options params of parser instance + */ + renderToken(tokens: Token[], idx: number, options: MarkdownIt.Options): string; + + /** + * The same as [[Renderer.render]], but for single token of `inline` type. + * + * @param tokens list on block tokens to renter + * @param options params of parser instance + * @param env additional data from parsed input (references, for example) + */ + renderInline(tokens: Token[], options: MarkdownIt.Options, env: any): string; + + /** + * Special kludge for image `alt` attributes to conform CommonMark spec. + * Don't try to use it! Spec requires to show `alt` content with stripped markup, + * instead of simple escaping. + * + * @param tokens list on block tokens to renter + * @param options params of parser instance + * @param env additional data from parsed input (references, for example) + */ + renderInlineAsText(tokens: Token[], options: MarkdownIt.Options, env: any): string; + + /** + * Takes token stream and generates HTML. Probably, you will never need to call + * this method directly. + * + * @param tokens list on block tokens to renter + * @param options params of parser instance + * @param env additional data from parsed input (references, for example) + */ + render(tokens: Token[], options: MarkdownIt.Options, env: any): string; } + +export = Renderer; diff --git a/types/markdown-it/lib/ruler.d.ts b/types/markdown-it/lib/ruler.d.ts index 62ab55e3de..3d644c42f8 100644 --- a/types/markdown-it/lib/ruler.d.ts +++ b/types/markdown-it/lib/ruler.d.ts @@ -1,15 +1,169 @@ -import MarkdownIt = require("."); -import State = require("./rules_core/state_core"); +import StateCore = require('./rules_core/state_core'); + +declare namespace Ruler { + interface RuleOptions { + /** + * array with names of "alternate" chains. + */ + alt: string[]; + } +} + +/** + * class Ruler + * + * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and + * [[MarkdownIt#inline]] to manage sequences of functions (rules): + * + * - keep rules in defined order + * - assign the name to each rule + * - enable/disable rules + * - add/replace rules + * - allow assign rules to additional named chains (in the same) + * - cacheing lists of active rules + * + * You will not need use this class directly until write plugins. For simple + * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and + * [[MarkdownIt.use]]. + */ +declare class Ruler { + /** + * Replace rule by name with new function & options. Throws error if name not + * found. + * + * ##### Example + * + * Replace existing typographer replacement rule with new one: + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.core.ruler.at('replacements', function replace(state) { + * //... + * }); + * ``` + * + * @param name rule name to replace. + * @param fn new rule function. + * @param options new rule options (not mandatory). + */ + at(name: string, fn: T, options?: Ruler.RuleOptions): void; + + /** + * Add new rule to chain before one with given name. See also + * [[Ruler.after]], [[Ruler.push]]. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.block.ruler.before('paragraph', 'my_rule', function replace(state) { + * //... + * }); + * ``` + * + * @param beforeName new rule will be added before this one. + * @param ruleName name of added rule. + * @param fn rule function. + * @param options rule options (not mandatory). + */ + before(beforeName: string, ruleName: string, fn: T, options?: Ruler.RuleOptions): void; + + /** + * Add new rule to chain after one with given name. See also + * [[Ruler.before]], [[Ruler.push]]. + * + * ##### Options: + * + * - __alt__ - array with names of "alternate" chains. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.inline.ruler.after('text', 'my_rule', function replace(state) { + * //... + * }); + * ``` + * + * @param afterName new rule will be added after this one. + * @param ruleName name of added rule. + * @param fn rule function. + * @param options rule options (not mandatory). + */ + after(afterName: string, ruleName: string, fn: T, options?: Ruler.RuleOptions): void; + + /** + * Push new rule to the end of chain. See also + * [[Ruler.before]], [[Ruler.after]]. + * + * ##### Options: + * + * - __alt__ - array with names of "alternate" chains. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.core.ruler.push('my_rule', function replace(state) { + * //... + * }); + * ``` + * + * @param ruleName name of added rule. + * @param fn rule function. + * @param options rule options (not mandatory). + */ + push(ruleName: string, fn: T, options?: Ruler.RuleOptions): void; + + /** + * Enable rules with given names. If any rule name not found - throw Error. + * Errors can be disabled by second param. + * + * Returns list of found rule names (if no exception happened). + * + * See also [[Ruler.disable]], [[Ruler.enableOnly]]. + * + * @param list list of rule names to enable. + * @param ignoreInvalid set `true` to ignore errors when rule not found. + */ + enable(list: string | string[], ignoreInvalid?: boolean): string[]; + + /** + * Enable rules with given names, and disable everything else. If any rule name + * not found - throw Error. Errors can be disabled by second param. + * + * See also [[Ruler.disable]], [[Ruler.enable]]. + * + * @param list list of rule names to enable (whitelist). + * @param ignoreInvalid set `true` to ignore errors when rule not found. + */ + enableOnly(list: string | string[], ignoreInvalid?: boolean): string[]; + + /** + * Disable rules with given names. If any rule name not found - throw Error. + * Errors can be disabled by second param. + * + * Returns list of found rule names (if no exception happened). + * + * See also [[Ruler.enable]], [[Ruler.enableOnly]]. + * + * @param list list of rule names to disable. + * @param ignoreInvalid set `true` to ignore errors when rule not found. + */ + disable(list: string | string[], ignoreInvalid?: boolean): string[]; + + /** + * Return array of active functions (rules) for given chain name. It analyzes + * rules configuration, compiles caches if not exists and returns result. + * + * Default chain name is `''` (empty string). It can't be skipped. That's + * done intentionally, to keep signature monomorphic for high speed. + */ + getRules(chainName: string): T[]; +} export = Ruler; - -declare class Ruler { - after(afterName: string, ruleName: string, rule: MarkdownIt.Rule, options?: any): void; - at(name: string, rule: MarkdownIt.Rule, options?: any): void; - before(beforeName: string, ruleName: string, rule: MarkdownIt.Rule, options?: any): void; - disable(rules: string | string[], ignoreInvalid?: boolean): string[]; - enable(rules: string | string[], ignoreInvalid?: boolean): string[]; - enableOnly(rule: string, ignoreInvalid?: boolean): void; - getRules(chain: string): MarkdownIt.Rule[]; - push(ruleName: string, rule: MarkdownIt.Rule, options?: any): void; -} diff --git a/types/markdown-it/lib/rules_block/state_block.d.ts b/types/markdown-it/lib/rules_block/state_block.d.ts index 6eebab4202..907054ace7 100644 --- a/types/markdown-it/lib/rules_block/state_block.d.ts +++ b/types/markdown-it/lib/rules_block/state_block.d.ts @@ -1,23 +1,134 @@ -import MarkdownIt = require(".."); -import State = require("../rules_core/state_core"); -import Token = require("../token"); +import MarkdownIt = require('..'); +import Token = require('../token'); + +declare namespace StateBlock { + type ParentType = 'blockquote' | 'list' | 'root' | 'paragraph' | 'reference'; +} + +declare class StateBlock { + constructor(src: string, md: MarkdownIt, env: any, tokens: Token[]); + + src: string; + + /** + * link to parser instance + */ + md: MarkdownIt; + + env: any; + + // + // Internal state vartiables + // + + tokens: Token[]; + + /** + * line begin offsets for fast jumps + */ + bMarks: number[]; + /** + * line end offsets for fast jumps + */ + eMarks: number[]; + /** + * offsets of the first non-space characters (tabs not expanded) + */ + tShift: number[]; + /** + * indents for each line (tabs expanded) + */ + sCount: number[]; + + /** + * An amount of virtual spaces (tabs expanded) between beginning + * of each line (bMarks) and real beginning of that line. + * + * It exists only as a hack because blockquotes override bMarks + * losing information in the process. + * + * It's used only when expanding tabs, you can think about it as + * an initial tab length, e.g. bsCount=21 applied to string `\t123` + * means first tab should be expanded to 4-21%4 === 3 spaces. + */ + bsCount: number[]; + + // block parser variables + + /** + * required block content indent (for example, if we are + * inside a list, it would be positioned after list marker) + */ + blkIndent: number; + /** + * line index in src + */ + line: number; + /** + * lines count + */ + lineMax: number; + /** + * loose/tight mode for lists + */ + tight: boolean; + /** + * indent of the current dd block (-1 if there isn't any) + */ + ddIndent: number; + /** + * indent of the current list block (-1 if there isn't any) + */ + listIndent: number; + + /** + * can be 'blockquote', 'list', 'root', 'paragraph' or 'reference' + * used in lists to determine if they interrupt a paragraph + */ + parentType: StateBlock.ParentType; + + level: number; + + /** + * renderer + */ + result: string; + + /** + * Push new token to "stream". + */ + push(type: string, tag: string, nesting: Token.Nesting): Token; + + isEmpty(line: number): boolean; + + skipEmptyLines(from: number): number; + + /** + * Skip spaces from given position. + */ + skipSpaces(pos: number): number; + + /** + * Skip spaces from given position in reverse. + */ + skipSpacesBack(pos: number, min: number): number; + + /** + * Skip char codes from given position + */ + skipChars(pos: number, code: number): number; + + /** + * Skip char codes reverse from given position - 1 + */ + skipCharsBack(pos: number, code: number, min: number): number; + + /** + * cut lines range from source. + */ + getLines(begin: number, end: number, indent: number, keepLastLF: boolean): string; + + Token: typeof Token; +} export = StateBlock; - -declare class StateBlock extends State { - /** Used in lists to determine if they interrupt a paragraph */ - parentType: 'blockquote' | 'list' | 'root' | 'paragraph' | 'reference'; - - eMarks: number[]; - bMarks: number[]; - bsCount: number[]; - sCount: number[]; - tShift: number[]; - - blkIndent: number; - ddIndent: number; - - line: number; - lineMax: number; - tight: boolean; -} diff --git a/types/markdown-it/lib/rules_core/state_core.d.ts b/types/markdown-it/lib/rules_core/state_core.d.ts index 19e28a4c7b..3d6dcb63d5 100644 --- a/types/markdown-it/lib/rules_core/state_core.d.ts +++ b/types/markdown-it/lib/rules_core/state_core.d.ts @@ -1,23 +1,20 @@ -import MarkdownIt = require(".."); -import Token = require("../token"); - -export = StateCore; +import MarkdownIt = require('..'); +import Token = require('../token'); declare class StateCore { - - constructor(src: string, md: MarkdownIt, env: any) + constructor(src: string, md: MarkdownIt, env: any); + src: string; env: any; - level: number; + tokens: Token[]; + inlineMode: boolean; - /** Link to parser instance */ + /** + * link to parser instance + */ md: MarkdownIt; - /** The markdown source code that is being parsed. */ - src: string; - - tokens: Token[]; - - /** Return any for a yet untyped property */ - [undocumented: string]: any; + Token: typeof Token; } + +export = StateCore; diff --git a/types/markdown-it/lib/rules_inline/state_inline.d.ts b/types/markdown-it/lib/rules_inline/state_inline.d.ts index 27938d99da..727eb0acbc 100644 --- a/types/markdown-it/lib/rules_inline/state_inline.d.ts +++ b/types/markdown-it/lib/rules_inline/state_inline.d.ts @@ -1,46 +1,78 @@ -import MarkdownIt = require(".."); -import State = require("../rules_core/state_core"); -import Token = require("../token"); +import MarkdownIt = require('..'); +import Token = require('../token'); -export = StateInline; +declare namespace StateInline { + interface Scanned { + can_open: boolean; + can_close: boolean; + length: number; + } -declare class StateInline extends State { - /** - * Stores `{ start: end }` pairs. Useful for backtrack - * optimization of pairs parse (emphasis, strikes). - */ - cache: { [start: number]: number }; + interface Delimiter { + marker: number; + length: number; + jump: number; + token: number; + end: number; + open: boolean; + close: boolean; + } - /** Emphasis-like delimiters */ - delimiters: MarkdownIt.Delimiter[]; + interface TokenMata { + delimiters: Delimiter[]; + } +} +declare class StateInline { + constructor(src: string, md: MarkdownIt, env: any, outTokens: Token[]); + + src: string; + env: any; + md: MarkdownIt; + tokens: Token[]; + tokens_meta: StateInline.TokenMata[]; + + pos: number; + posMax: number; + level: number; pending: string; pendingLevel: number; - /** Index of the first character of this token. */ - pos: number; - - /** Index of the last character that can be used (for example the one before the end of this line). */ - posMax: number; + /** + * Stores { start: end } pairs. Useful for backtrack + * optimization of pairs parse (emphasis, strikes). + */ + cache: any; /** - * Push new token to "stream". - * If pending text exists, flush it as text token. + * List of emphasis-like delimiters for current tag */ - push(type: string, tag: string, nesting: number): Token; + delimiters: StateInline.Delimiter[]; - /** Flush pending text */ + // Stack of delimiter lists for upper level tags + // _prev_delimiters: StateInline.Delimiter[][]; + + /** + * Flush pending text + */ pushPending(): Token; /** - * Scan a sequence of emphasis-like markers and determine whether - * it can start an emphasis sequence or end an emphasis sequence. - * @param start - position to scan from (it should point to a valid marker) - * @param canSplitWord - determine if these markers can be found inside a word + * Push new token to "stream". + * If pending text exists - flush it as text token */ - scanDelims(start: number, canSplitWord: boolean): { - can_open: boolean, - can_close: boolean, - length: number - }; + push(type: string, tag: string, nesting: Token.Nesting): Token; + + /** + * Scan a sequence of emphasis-like markers, and determine whether + * it can start an emphasis sequence or end an emphasis sequence. + * + * @param start position to scan from (it should point at a valid marker); + * @param canSplitWord determine if these markers can be found inside a word + */ + scanDelims(start: number, canSplitWord: boolean): StateInline.Scanned; + + Token: typeof Token; } + +export = StateInline; diff --git a/types/markdown-it/lib/token.d.ts b/types/markdown-it/lib/token.d.ts index 1f71d54bfd..5f1e16275d 100644 --- a/types/markdown-it/lib/token.d.ts +++ b/types/markdown-it/lib/token.d.ts @@ -1,23 +1,111 @@ -export = Token; - -declare class Token { - constructor(type: string, tag: string, nesting: number); - attrGet: (name: string) => string | null; - attrIndex: (name: string) => number; - attrJoin: (name: string, value: string) => void; - attrPush: (attrData: string[]) => void; - attrSet: (name: string, value: string) => void; - attrs: string[][]; - block: boolean; - children: Token[]; - content: string; - hidden: boolean; - info: string; - level: number; - map: number[]; - markup: string; - meta: any; - nesting: number; - tag: string; - type: string; +declare namespace Token { + type Nesting = 1 | 0 | -1; } + +/** + * Create new token and fill passed properties. + */ +declare class Token { + constructor(type: string, tag: string, nesting: Token.Nesting); + + /** + * Type of the token, e.g. "paragraph_open" + */ + type: string; + + /** + * HTML tag name, e.g. "p" + */ + tag: string; + + /** + * HTML attributes. Format: `[[name1, value1], [name2, value2]]` + */ + attrs: [string, string][] | null; + + /** + * Source map info. Format: `[line_begin, line_end]` + */ + map: [number, number] | null; + + /** + * Level change (number in {-1, 0, 1} set), where: + * + * - `1` means the tag is opening + * - `0` means the tag is self-closing + * - `-1` means the tag is closing + */ + nesting: 1 | 0 | -1; + + /** + * nesting level, the same as `state.level` + */ + level: number; + + /** + * An array of child nodes (inline and img tokens) + */ + children: Token[] | null; + + /** + * In a case of self-closing tag (code, html, fence, etc.), + * it has contents of this tag. + */ + content: string; + + /** + * '*' or '_' for emphasis, fence string for fence, etc. + */ + markup: string; + + /** + * Fence info string + */ + info: string; + + /** + * A place for plugins to store an arbitrary data + */ + meta: any; + + /** + * True for block-level tokens, false for inline tokens. + * Used in renderer to calculate line breaks + */ + block: boolean; + + /** + * If it's true, ignore this element when rendering. Used for tight lists + * to hide paragraphs. + */ + hidden: boolean; + + /** + * Search attribute index by name. + */ + attrIndex(name: string): number; + + /** + * Add `[name, value]` attribute to list. Init attrs if necessary + */ + attrPush(attrData: [string, string]): void; + + /** + * Set `name` attribute to `value`. Override old value if exists. + */ + attrSet(name: string, value: string): void; + + /** + * Get the value of attribute `name`, or null if it does not exist. + */ + attrGet(name: string): string | null; + + /** + * + * Join value to existing attribute via space. Or create new attribute if not + * exists. Useful to operate with token classes. + */ + attrJoin(name: string, value: string): void; +} + +export = Token; diff --git a/types/markdown-it/markdown-it-tests.ts b/types/markdown-it/markdown-it-tests.ts index 343661ad87..f427b8132a 100644 --- a/types/markdown-it/markdown-it-tests.ts +++ b/types/markdown-it/markdown-it-tests.ts @@ -1,32 +1,49 @@ -import MarkdownIt = require("markdown-it"); -import Renderer = require("markdown-it/lib/renderer"); -import Token = require("markdown-it/lib/token"); +import MarkdownIt = require('markdown-it'); +import MarkdownIt1 = require('markdown-it/index'); +import MarkdownIt2 = require('markdown-it/lib'); +import MarkdownIt3 = require('markdown-it/lib/index'); + +import hljs = require('highlight.js'); +import LinkifyIt = require('linkify-it'); { - const md = new MarkdownIt(); - var result = md.render('# markdown-it rulezz!'); + // check exports + let md: typeof MarkdownIt; + md = MarkdownIt1; + md = MarkdownIt2; + md = MarkdownIt3; } { - var md = MarkdownIt(); - var result = md.render('# markdown-it rulezz!'); - var result = md.renderInline('__markdown-it__ rulezz!'); -} + // test constuctor usage + let md: MarkdownIt; + const options: MarkdownIt.Options = {}; + const presets: MarkdownIt.PresetName[] = ['commonmark', 'zero', 'default']; -{ - var md = MarkdownIt('commonmark'); -} + md = MarkdownIt(); + md = new MarkdownIt(); + md = MarkdownIt(options); + md = new MarkdownIt(options); -{ - var md = MarkdownIt({ + presets.forEach(p => { + md = MarkdownIt(p); + md = new MarkdownIt(p); + md = MarkdownIt(p, options); + md = new MarkdownIt(p, options); + }); + + md = MarkdownIt({ html: true, linkify: true, - typographer: true + typographer: true, + }); + md = new MarkdownIt({ + html: true, + linkify: true, + typographer: true, }); -} -{ - var md = MarkdownIt({ + md = MarkdownIt({ html: false, xhtmlOut: false, breaks: false, @@ -34,9 +51,24 @@ import Token = require("markdown-it/lib/token"); linkify: false, typographer: false, quotes: '“”‘’', - highlight: function () { return ''; } + highlight: function(str: string, lang: string): string { + return ''; + }, + }); + md = new MarkdownIt({ + html: false, + xhtmlOut: false, + breaks: false, + langPrefix: 'language-', + linkify: false, + typographer: false, + quotes: '“”‘’', + highlight: function(str: string, lang: string): string { + return ''; + }, }); } + declare const plugin1: any; declare const plugin2: any; declare const plugin3: any; @@ -48,121 +80,47 @@ declare const opts: any; .use(plugin3); } -import * as hljs from 'highlight.js'; { var md = MarkdownIt({ - highlight: function (str, lang) { + highlight: function(str, lang) { if (lang && hljs.getLanguage(lang)) { try { - return hljs.highlight(lang, str).value; - } catch (__) { } + return hljs.highlight(lang, str, true).value; + } catch (__) {} } - return ''; // use external default escaping - } + return ''; + }, + }); +} +{ + var md = MarkdownIt({ + highlight: function(str, lang) { + if (lang && hljs.getLanguage(lang)) { + try { + return '
' + hljs.highlight(lang, str, true).value + '
'; + } catch (__) {} + } + + return '
' + md.utils.escapeHtml(str) + '
'; + }, }); } { - var md = MarkdownIt({ - highlight: function (str, lang) { - if (lang && hljs.getLanguage(lang)) { - try { - return '
' +
-                        hljs.highlight(lang, str, true).value +
-                        '
'; - } catch (__) { } - } - - return '
' + md.utils.escapeHtml(str) + '
'; - } - }); + const linkify: LinkifyIt.LinkifyIt = md.linkify; md.linkify.tlds('.py', false); } { - var md = MarkdownIt() + let md = MarkdownIt() .disable(['link', 'image']) .enable(['link']) .enable('image'); - // Enable everything md = MarkdownIt({ html: true, linkify: true, typographer: true, }); } - -{ - var md = MarkdownIt() - .set({ html: true, breaks: true }) - .set({ typographer: true }); -} - -{ - var md = MarkdownIt() - .use(plugin1, 'foo_replace', 'text', function (tokens: any[], idx: number) { - tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar'); - }); -} - -{ - var md = MarkdownIt(); - // enable everything - md.validateLink = function () { return true; } -} - -function myToken(tokens: any, idx: number, options: any, env: any, self: any) { - //... - return result; -}; -{ - var md = MarkdownIt(); - md.renderer.rules['my_token'] = myToken -} - -{ - const md = MarkdownIt({ - linkify: true, - highlight: (str: string, lang: string) => { - if (hljs) { - if (lang && hljs.getLanguage(lang)) { - try { - return hljs.highlight(lang, str).value; - } catch (error) { - console.log(error); - } - } - try { - return hljs.highlightAuto(str).value; - } catch (error) { - console.log(error); - } - } - return ""; - }, - }); - md.renderer.rules["image"] = (tokens: Token[], index: number, options: any, env: any, self: Renderer) => { - const token = tokens[index]; - const aIndex = token.attrIndex("src"); - token.attrs[aIndex][1]; - token.attrPush(["style", "color: red"]); - - return md.renderer.rules["image"](tokens, index, options, env, self); - }; - - let defaultLinkRender: MarkdownIt.TokenRender; - if (md.renderer.rules["link_open"]) { - defaultLinkRender = md.renderer.rules["link_open"]; - } else { - defaultLinkRender = (tokens: Token[], index: number, options: any, env: any, self: Renderer) => { - return self.renderToken(tokens, index, options); - }; - } - md.renderer.rules["link_open"] = (tokens: Token[], index: number, options: any, env: any, self: Renderer) => { - tokens[index].attrPush(["target", "_blank"]); - tokens[index].attrPush(["rel", "nofollow"]); - return defaultLinkRender(tokens, index, options, env, self); - }; -} diff --git a/types/markdown-it/test/common/utils.ts b/types/markdown-it/test/common/utils.ts new file mode 100644 index 0000000000..3ad3fddfea --- /dev/null +++ b/types/markdown-it/test/common/utils.ts @@ -0,0 +1,42 @@ +import utils = require('markdown-it/lib/common/utils'); + +import entities = require('markdown-it/lib/common/entities'); +import htmlBlocks = require('markdown-it/lib/common/html_blocks'); +import htmlRE = require('markdown-it/lib/common/html_re'); +import StateBlock = require('markdown-it/lib/rules_block/state_block'); +import StateInline = require('markdown-it/lib/rules_inline/state_inline'); + +utils.lib.mdurl.parse('https://github.com/markdown-it/markdown-it', true); + +const options = utils.assign({}, {}); +utils.isString(options); +utils.has(options, 'foobar'); +utils.unescapeMd('# Foobar'); +utils.unescapeAll('foobar'); +utils.isValidEntityCode(1); +utils.fromCodePoint(0xfffd); +utils.escapeHtml('
foobar
'); +utils.arrayReplaceAt([1], 0, [1, 2, 3]); +utils.isSpace('foobar'.charCodeAt(0)); +utils.isWhiteSpace('foobar'.charCodeAt(0)); +utils.isMdAsciiPunct('foobar'.charCodeAt(0)); +utils.isPunctChar(String.fromCharCode(0x20)); +utils.escapeRE('foobar'); +utils.normalizeReference('foobar'); + +const encoded = '
foo&bar
'.replace(entities.amp, `&`); + +const blocks: string[] = htmlBlocks; + +declare const stateBlock: StateBlock; +{ + const re = new RegExp(htmlRE.HTML_OPEN_CLOSE_TAG_RE.source + '\\s*$'); +} + +declare const stateInline: StateInline; +{ + const match = stateInline.src.slice(stateInline.pos).match(htmlRE.HTML_TAG_RE); + if (match) { + stateInline.pos += match[0].length; + } +} diff --git a/types/markdown-it/test/helpers/index.ts b/types/markdown-it/test/helpers/index.ts new file mode 100644 index 0000000000..b5750d2614 --- /dev/null +++ b/types/markdown-it/test/helpers/index.ts @@ -0,0 +1,8 @@ +import State = require('markdown-it/lib/rules_core/state_core'); +import helpers = require('markdown-it/lib/helpers'); + +declare const state: State; + +helpers.parseLinkLabel(state, 0, true); +helpers.parseLinkDestination('https://github.com/markdown-it/markdown-it', 0, 3); +helpers.parseLinkTitle('https://github.com/markdown-it/markdown-it', 0, 3); diff --git a/types/markdown-it/test/index.ts b/types/markdown-it/test/index.ts new file mode 100644 index 0000000000..d818113c85 --- /dev/null +++ b/types/markdown-it/test/index.ts @@ -0,0 +1,137 @@ +import MarkdownIt = require('markdown-it/lib'); +import ParserInline = require('markdown-it/lib/parser_inline'); +import ParserBlock = require('markdown-it/lib/parser_block'); +import ParserCore = require('markdown-it/lib/parser_core'); +import Renderer = require('markdown-it/lib/renderer'); +import LinkifyIt = require('linkify-it'); + +{ + const md = new MarkdownIt(); + let options: MarkdownIt.Options; + // all empty + options = {}; + + // Commonmark + options = { + html: true, + xhtmlOut: true, + breaks: false, + langPrefix: 'language-', + linkify: false, + typographer: false, + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + highlight: null, + }; + + // Zero + options = { + html: false, + xhtmlOut: false, + breaks: false, + langPrefix: 'language-', + linkify: false, + typographer: false, + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + highlight: null, + }; + + // default + options = { + html: false, + xhtmlOut: false, + breaks: false, + langPrefix: 'language-', + linkify: false, + typographer: false, + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + highlight: null, + }; +} + +{ + const md = new MarkdownIt(); + + const inline: ParserInline = md.inline; + const block: ParserBlock = md.block; + const core: ParserCore = md.core; + const renderer: Renderer = md.renderer; + + const linkify: LinkifyIt.LinkifyIt = md.linkify; + + const options: MarkdownIt.Options = md.options; +} + +{ + const md = MarkdownIt() + .set({ html: true, breaks: true }) + .set({ typographer: true }); +} + +{ + const md = MarkdownIt() + .configure('default') + .configure('zero') + .configure('commonmark'); +} + +{ + const md = MarkdownIt() + .enable(['sub', 'sup']) + .enable(['sub', 'sup'], true) + .disable(['sub', 'sup']) + .disable(['sub', 'sup'], true) + .enable('smartquotes') + .enable('smartquotes', true) + .disable('smartquotes') + .disable('smartquotes', true); +} + +{ + // Test plugin generic types + + const plugin: MarkdownIt.PluginSimple = (md: MarkdownIt) => {}; + const plugin1 = (md: MarkdownIt, param?: boolean) => {}; + const plugin2 = (md: MarkdownIt, param1?: string, param2?: number) => {}; + const plugin3 = (md: MarkdownIt, ...params: any[]) => {}; + const plugin4: MarkdownIt.PluginWithOptions<{ foo: boolean; bar: number }> = (md, options) => {}; + const plugin5: MarkdownIt.PluginWithParams = (md, flag?: boolean, str?: string, num?: number) => {}; + + const md = MarkdownIt() + .use(plugin) + .use(plugin, 'foobar') + .use(plugin1, false) + .use(plugin2, 'foobar', 123) + .use(plugin3, {}) + .use(plugin4) + .use(plugin4, { foo: true, bar: 123 }) + .use(plugin5) + .use(plugin5, true, 'foobar', 123); +} + +{ + const md = new MarkdownIt(); + const flag: boolean = md.validateLink('https://github.com/'); + const link: string = md.normalizeLink('https://github.com/'); + const text: string = md.normalizeLinkText('http://host/'); +} + +{ + const md = new MarkdownIt(); + + let result: string; + result = md.render('# Foobar'); + result = md.render('# Foobar', {}); + + const tokens = md.parse('# Foobar', {}); + result = md.renderer.render(tokens, md.options, {}); +} +{ + const md = new MarkdownIt(); + + let result: string; + result = md.renderInline('__foobar__'); + result = md.renderInline('__foobar__', {}); + + const tokens = md.parseInline('__foobar__', {}); + result = md.renderer.renderInline(tokens, md.options, {}); +} diff --git a/types/markdown-it/test/parser_block.ts b/types/markdown-it/test/parser_block.ts new file mode 100644 index 0000000000..cd54d44348 --- /dev/null +++ b/types/markdown-it/test/parser_block.ts @@ -0,0 +1,16 @@ +import MarkdownIt = require('markdown-it/lib'); +import Token = require('markdown-it/lib/token'); +import StateBlock = require('markdown-it/lib/rules_block/state_block'); +import ParserBlock = require('markdown-it/lib/parser_block'); + +const md = new MarkdownIt(); +const tokens: Token[] = []; +const state: StateBlock = new md.block.State('# Foobar', md, {}, tokens); +md.block.tokenize(state, state.line, state.lineMax); +state.md.block.parse(state.src, state.md, state.env, state.tokens); + +const rule: ParserBlock.RuleBlock = (state: StateBlock, startLine: number, endLine: number, silent: boolean) => { + return false; +}; + +md.block.ruler.push('foobar', rule, { alt: ['paragraph', 'reference'] }); diff --git a/types/markdown-it/test/parser_core.ts b/types/markdown-it/test/parser_core.ts new file mode 100644 index 0000000000..a0256c64c8 --- /dev/null +++ b/types/markdown-it/test/parser_core.ts @@ -0,0 +1,14 @@ +import MarkdownIt = require('markdown-it/lib'); +import Token = require('markdown-it/lib/token'); +import StateCore = require('markdown-it/lib/rules_core/state_core'); +import ParserCore = require('markdown-it/lib/parser_core'); + +const md = new MarkdownIt(); +const state: StateCore = new md.core.State('# Foobar', md, {}); +md.core.process(state); + +const rule: ParserCore.RuleCore = (state: StateCore): boolean => { + return false; +}; + +md.core.ruler.push('foobar', rule); diff --git a/types/markdown-it/test/parser_inline.ts b/types/markdown-it/test/parser_inline.ts new file mode 100644 index 0000000000..93058aceba --- /dev/null +++ b/types/markdown-it/test/parser_inline.ts @@ -0,0 +1,20 @@ +import MarkdownIt = require('markdown-it/lib'); +import Token = require('markdown-it/lib/token'); +import StateInline = require('markdown-it/lib/rules_inline/state_inline'); +import ParserInline = require('markdown-it/lib/parser_inline'); + +const md = new MarkdownIt(); +const tokens: Token[] = []; +const state: StateInline = new md.inline.State('__foobar', md, {}, tokens); + +const rule: ParserInline.RuleInline = (state: StateInline, silent: boolean) => { + return false; +}; + +md.inline.ruler.push('foobar', rule); + +const rule2: ParserInline.RuleInline2 = (state: StateInline) => { + return false; +}; + +md.inline.ruler2.push('foobar', rule2); diff --git a/types/markdown-it/test/renderer.ts b/types/markdown-it/test/renderer.ts new file mode 100644 index 0000000000..0cbdfa02d4 --- /dev/null +++ b/types/markdown-it/test/renderer.ts @@ -0,0 +1,68 @@ +import MarkdownIt = require('markdown-it'); +import Renderer = require('markdown-it/lib/renderer'); +import Token = require('markdown-it/lib/token'); + +const md = new MarkdownIt(); +const src = '# Foobar'; +const env = {}; + +{ + md.renderer.rules.strong_open = () => ''; + md.renderer.rules.strong_close = () => ''; + const result = md.renderInline('__foobar__'); +} + +{ + md.renderer.rules.foobar = ( + tokens: Token[], + idx: number, + options: MarkdownIt.Options, + env: any, + slf: Renderer, + ): string => { + return 'foobar'; + }; +} + +{ + const result = md.renderer.render(md.parse(src, env), md.options, env); +} + +{ + const result = md.renderer.render(md.parseInline(src, env), md.options, env); +} + +{ + const tokens = md.parse(src, env); + let result = ''; + for (const token of tokens) { + if (token.type === 'inline' && token.children) { + result += md.renderer.renderInline(token.children, md.options, env); + } + } +} + +{ + const tokens = md.parse(src, env); + let result = ''; + for (const token of tokens) { + if (token.type === 'image' && token.children) { + result += md.renderer.renderInlineAsText(token.children, md.options, env); + } + } +} + +{ + const tokens = md.parse(src, env); + let result = ''; + for (let index = 0; index < tokens.length; index++) { + result += md.renderer.renderToken(tokens, index, md.options); + } +} + +{ + const tokens = md.parse(src, env); + for (const token of tokens) { + const attr = md.renderer.renderAttrs(token); + } +} diff --git a/types/markdown-it/test/ruler.ts b/types/markdown-it/test/ruler.ts new file mode 100644 index 0000000000..40b51df835 --- /dev/null +++ b/types/markdown-it/test/ruler.ts @@ -0,0 +1,36 @@ +import MarkdownIt = require('markdown-it'); +import Ruler = require('markdown-it/lib/ruler'); + +const md = new MarkdownIt(); + +md.core.ruler.at('replacements', function replace(state) { + //... + return true; +}); + +md.block.ruler.before('paragraph', 'my_rule', function replace(state) { + //... + return true; +}); + +md.inline.ruler.after('text', 'my_rule', function replace(state) { + //... + return true; +}); + +md.core.ruler.push('my_rule', function replace(state) { + //... + return true; +}); + +md.core.ruler.enable(['link']); +md.core.ruler.enable('image'); +md.core.ruler.enableOnly(['link']); +md.core.ruler.enableOnly('image'); +md.core.ruler.disable(['link', 'image']); +md.core.ruler.disable('link'); + +const coreRules = md.core.ruler.getRules(''); +const terminatorRules = md.block.ruler.getRules('blockquote'); + +md.core.ruler.push('foobar', state => false, { alt: ['foo', 'bar'] }); diff --git a/types/markdown-it/test/rules_block/state_block.ts b/types/markdown-it/test/rules_block/state_block.ts new file mode 100644 index 0000000000..a66cc27f7c --- /dev/null +++ b/types/markdown-it/test/rules_block/state_block.ts @@ -0,0 +1,61 @@ +import MarkdownIt = require('markdown-it'); +import Token = require('markdown-it/lib/token'); + +import StateBlock = require('markdown-it/lib/rules_block/state_block'); + +const md = new MarkdownIt(); +const tokens: Token[] = []; + +const state = new StateBlock('# Foobar', md, {}, tokens); + +{ + state.src = '# Foobar'; + state.md = md; + state.env = {}; + state.tokens = tokens; + + state.bMarks = [] as number[]; + state.eMarks = [] as number[]; + state.tShift = [] as number[]; + state.sCount = [] as number[]; + + state.bsCount = [] as number[]; + + state.blkIndent = 0; + + state.line = 0; + state.lineMax = 0; + state.tight = false; + state.ddIndent = -1; + state.listIndent = -1; + + state.parentType = 'root'; + + state.level = 0; + + state.result = ''; + + state.bMarks.push(16); + state.eMarks.push(16); + state.tShift.push(0); + state.sCount.push(0); + state.bsCount.push(0); + + state.lineMax = state.bMarks.length - 1; +} + +{ + let token: Token; + let flag: boolean; + let num: number; + + token = state.push('hr', 'hr', 0); + flag = state.isEmpty(2); + num = state.skipEmptyLines(123); + num = state.skipSpaces(456); + num = state.skipSpacesBack(789, 456); + num = state.skipChars(234, '*'.charCodeAt(0)); + num = state.skipCharsBack(345, '_'.charCodeAt(0), 456); + + token = new state.Token('hr', 'hr', 0); +} diff --git a/types/markdown-it/test/rules_core/state_core.ts b/types/markdown-it/test/rules_core/state_core.ts new file mode 100644 index 0000000000..82a397d7d9 --- /dev/null +++ b/types/markdown-it/test/rules_core/state_core.ts @@ -0,0 +1,21 @@ +import MarkdownIt = require('markdown-it'); +import Token = require('markdown-it/lib/token'); + +import StateCore = require('markdown-it/lib/rules_core/state_core'); + +const md = new MarkdownIt(); + +const state = new StateCore('# Foobar', md, {}); + +{ + state.src = '# Foobar'; + state.env = {}; + state.tokens = [] as Token[]; + state.inlineMode = false; + state.md = md; +} + +{ + let token = new state.Token('heading_open', 'h1', -1); + state.tokens.push(token); +} diff --git a/types/markdown-it/test/rules_inline/state_inline.ts b/types/markdown-it/test/rules_inline/state_inline.ts new file mode 100644 index 0000000000..922c525a64 --- /dev/null +++ b/types/markdown-it/test/rules_inline/state_inline.ts @@ -0,0 +1,54 @@ +import MarkdownIt = require('markdown-it'); +import Token = require('markdown-it/lib/token'); + +import StateInline = require('markdown-it/lib/rules_inline/state_inline'); + +const md = new MarkdownIt(); +const tokens: Token[] = []; + +const state = new StateInline('__foobar__', md, {}, tokens); + +{ + state.src = '__foobar__'; + state.env = {}; + state.md = md; + state.tokens = tokens; + state.tokens_meta = [] as StateInline.TokenMata[]; + state.pos = 0; + state.posMax = state.src.length; + state.level = 0; + state.pending = ''; + state.pendingLevel = 0; + state.cache = {}; + state.delimiters = [] as StateInline.Delimiter[]; +} + +{ + let token: Token; + if (state.pending) { + token = state.pushPending(); + } + token = state.push('image', 'img', 0); + token = new state.Token('image', 'img', 0); +} + +{ + const marker = '*'.charCodeAt(0); + let scanned: StateInline.Scanned = { + can_open: true, + can_close: true, + length: 16, + }; + + scanned = state.scanDelims(state.pos, marker === 0x2a); + + state.delimiters.push({ + marker: marker, + length: scanned.length, + jump: 0, + token: state.tokens.length - 1, + end: -1, + open: scanned.can_open, + close: scanned.can_close, + }); +} diff --git a/types/markdown-it/test/token.ts b/types/markdown-it/test/token.ts new file mode 100644 index 0000000000..e76776f41c --- /dev/null +++ b/types/markdown-it/test/token.ts @@ -0,0 +1,23 @@ +import Token = require('markdown-it/lib/token'); + +const token = new Token('link_open', 'a', 1); + +token.type = 'paragraph_open'; +token.tag = 'p'; +token.attrs = null; +token.map = null; +token.nesting = 1; +token.level = 0; +token.children = null; +token.content = ''; +token.markup = ''; +token.info = ''; +token.meta = null; +token.block = false; +token.hidden = false; + +const index: number = token.attrIndex('href'); +token.attrPush(['data-foo', 'bar']); +token.attrSet('href', 'https://github.com/markdown-it/markdown-it'); +const href: string | null = token.attrGet('href'); +token.attrJoin('class', 'foobar'); diff --git a/types/markdown-it/tsconfig.json b/types/markdown-it/tsconfig.json index c4587f7a94..c37572e878 100644 --- a/types/markdown-it/tsconfig.json +++ b/types/markdown-it/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "module": "commonjs", + "target": "es6", "lib": [ "es6", "dom" @@ -19,6 +20,18 @@ }, "files": [ "index.d.ts", + "test/common/utils.ts", + "test/helpers/index.ts", + "test/rules_core/state_core.ts", + "test/rules_block/state_block.ts", + "test/rules_inline/state_inline.ts", + "test/index.ts", + "test/parser_block.ts", + "test/parser_core.ts", + "test/parser_inline.ts", + "test/renderer.ts", + "test/ruler.ts", + "test/token.ts", "markdown-it-tests.ts" ] } diff --git a/types/markdown-it/tslint.json b/types/markdown-it/tslint.json index 8caa8386a6..ab8943c366 100644 --- a/types/markdown-it/tslint.json +++ b/types/markdown-it/tslint.json @@ -20,4 +20,4 @@ "space-before-function-paren": false, "unified-signatures": false } -} \ No newline at end of file +} diff --git a/types/prosemirror-markdown/prosemirror-markdown-tests.ts b/types/prosemirror-markdown/prosemirror-markdown-tests.ts index 3f069f7bdd..ccb5e39e61 100644 --- a/types/prosemirror-markdown/prosemirror-markdown-tests.ts +++ b/types/prosemirror-markdown/prosemirror-markdown-tests.ts @@ -24,7 +24,7 @@ export const fromMarkdown = (markdown: string, schema: Schema) => getAttrs: tok => ({ src: tok.attrGet('src'), title: tok.attrGet('title') || null, - alt: (tok.children[0] && tok.children[0].content) || null, + alt: (tok.children && tok.children[0] && tok.children[0].content) || null, }), }, hardbreak: { node: 'hardBreak' },