From 1ce59ea827272b5d067f1e06d3ee4a1d52b1d9bb Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 12 Jun 2024 01:00:22 -0500 Subject: [PATCH] feat: Send token objects to renderers (#3291) BREAKING CHANGE: extensions that change marked renderers will need to be updated and use new option `useNewRenderer` --- docs/USING_PRO.md | 109 +++++----- package-lock.json | 459 ++++++++++++++++++--------------------- src/Instance.ts | 257 +++++++++++++++++++++- src/MarkedOptions.ts | 10 +- src/Parser.ts | 162 ++++---------- src/Renderer.ts | 146 +++++++++---- src/TextRenderer.ts | 18 +- src/Tokenizer.ts | 14 +- src/Tokens.ts | 18 +- test/types/marked.ts | 51 ++--- test/unit/Lexer.test.js | 72 ++++-- test/unit/Parser.test.js | 18 +- test/unit/marked.test.js | 25 ++- 13 files changed, 821 insertions(+), 538 deletions(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index c07f1d286d..792460d34f 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -68,16 +68,16 @@ import { marked } from 'marked'; // Override function const renderer = { - heading(text, level) { + heading({ text, depth }) { const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); return ` - + ${text} - `; + `; } }; @@ -97,7 +97,7 @@ console.log(marked.parse('# heading+')); heading+ ``` -**Note:** Calling `marked.use()` in the following way will avoid overriding the `heading` token output but create a new renderer in the process. +**Note:** Calling `marked.use()` in the following way will avoid overriding the `heading` token output but create a new `heading` renderer in the process. ```js marked.use({ @@ -112,38 +112,32 @@ marked.use({ ### Block-level renderer methods -- **code**(*string* code, *string* infostring, *boolean* escaped) -- **blockquote**(*string* quote) -- **html**(*string* html, *boolean* block) -- **heading**(*string* text, *number* level, *string* raw) -- **hr**() -- **list**(*string* body, *boolean* ordered, *number* start) -- **listitem**(*string* text, *boolean* task, *boolean* checked) -- **checkbox**(*boolean* checked) -- **paragraph**(*string* text) -- **table**(*string* header, *string* body) -- **tablerow**(*string* content) -- **tablecell**(*string* content, *object* flags) +- **space**(token: *Tokens.Space*): *string* +- **code**(token: *Tokens.Code*): *string* +- **blockquote**(token: *Tokens.Blockquote*): *string* +- **html**(token: *Tokens.HTML | Tokens.Tag*): *string* +- **heading**(token: *Tokens.Heading*): *string* +- **hr**(token: *Tokens.Hr*): *string* +- **list**(token: *Tokens.List*): *string* +- **listitem**(token: *Tokens.ListItem*): *string* +- **checkbox**(token: *Tokens.Checkbox*): *string* +- **paragraph**(token: *Tokens.Paragraph*): *string* +- **table**(token: *Tokens.Table*): *string* +- **tablerow**(token: *Tokens.TableRow*): *string* +- **tablecell**(token: *Tokens.TableCell*): *string* ### Inline-level renderer methods -- **strong**(*string* text) -- **em**(*string* text) -- **codespan**(*string* code) -- **br**() -- **del**(*string* text) -- **link**(*string* href, *string* title, *string* text) -- **image**(*string* href, *string* title, *string* text) -- **text**(*string* text) +- **strong**(token: *Tokens.Strong*): *string* +- **em**(token: *Tokens.Em*): *string* +- **codespan**(token: *Tokens.Codespan*): *string* +- **br**(token: *Tokens.Br*): *string* +- **del**(token: *Tokens.Del*): *string* +- **link**(token: *Tokens.Link*): *string* +- **image**(token: *Tokens.Image*): *string* +- **text**(token: *Tokens.Text | Tokens.Escape | Tokens.Tag*): *string* -`flags` has the following properties: - -```js -{ - header: true || false, - align: 'center' || 'left' || 'right' -} -``` +The Tokens.* properties can be found [here](https://github.com/markedjs/marked/blob/master/src/Tokens.ts). *** @@ -192,33 +186,35 @@ console.log(marked.parse('$ latex code $\n\n` other code `')); ### Block level tokenizer methods -- **space**(*string* src) -- **code**(*string* src) -- **fences**(*string* src) -- **heading**(*string* src) -- **hr**(*string* src) -- **blockquote**(*string* src) -- **list**(*string* src) -- **html**(*string* src) -- **def**(*string* src) -- **table**(*string* src) -- **lheading**(*string* src) -- **paragraph**(*string* src) -- **text**(*string* src) +- **space**(src: *string*): *Tokens.Space* +- **code**(src: *string*): *Tokens.Code* +- **fences**(src: *string*): *Tokens.Code* +- **heading**(src: *string*): *Tokens.Heading* +- **hr**(src: *string*): *Tokens.Hr* +- **blockquote**(src: *string*): *Tokens.Blockquote* +- **list**(src: *string*): *Tokens.List* +- **html**(src: *string*): *Tokens.HTML* +- **def**(src: *string*): *Tokens.Def* +- **table**(src: *string*): *Tokens.Table* +- **lheading**(src: *string*): *Tokens.Heading* +- **paragraph**(src: *string*): *Tokens.Paragraph* +- **text**(src: *string*): *Tokens.Text* ### Inline level tokenizer methods -- **escape**(*string* src) -- **tag**(*string* src) -- **link**(*string* src) -- **reflink**(*string* src, *object* links) -- **emStrong**(*string* src, *string* maskedSrc, *string* prevChar) -- **codespan**(*string* src) -- **br**(*string* src) -- **del**(*string* src) -- **autolink**(*string* src) -- **url**(*string* src) -- **inlineText**(*string* src) +- **escape**(src: *string*): *Tokens.Escape* +- **tag**(src: *string*): *Tokens.Tag* +- **link**(src: *string*): *Tokens.Link | Tokens.Image* +- **reflink**(src: *string*, links: *object*): *Tokens.Link | Tokens.Image | Tokens.Text* +- **emStrong**(src: *string*, maskedSrc: *string*, prevChar: *string*): *Tokens.Em | Tokens.Strong* +- **codespan**(src: *string*): *Tokens.Codespan* +- **br**(src: *string*): *Tokens.Br* +- **del**(src: *string*): *Tokens.Del* +- **autolink**(src: *string*): *Tokens.Link* +- **url**(src: *string*): *Tokens.Link* +- **inlineText**(src: *string*): *Tokens.Text* + +The Tokens.* properties can be found [here](https://github.com/markedjs/marked/blob/master/src/Tokens.ts). *** @@ -263,6 +259,7 @@ Hooks are methods that hook into some part of marked. The following hooks are av |-----------|-------------| | `preprocess(markdown: string): string` | Process markdown before sending it to marked. | | `postprocess(html: string): string` | Process html after marked has finished parsing. | +| `processAllTokens(tokens: Token[]): Token[]` | Process all tokens before walk tokens. | `marked.use()` can be called multiple times with different `hooks` functions. Each function will be called in order, starting with the function that was assigned *last*. diff --git a/package-lock.json b/package-lock.json index d61ca4ac01..5f1b58493a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5441,9 +5441,9 @@ } }, "node_modules/npm": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.5.0.tgz", - "integrity": "sha512-Ejxwvfh9YnWVU2yA5FzoYLTW52vxHCz+MHrOFg9Cc8IFgF/6f5AGPAvb5WTay5DIUP1NIfN3VBZ0cLlGO0Ys+A==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.7.0.tgz", + "integrity": "sha512-FXylyYSXNjgXx3l82BT8RSQvCoGIQ3h8YdRFGKNvo3Pv/bKscK4pdWkx/onwTpHDqGw+oeLf4Rxln9WVyxAxlQ==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -5452,6 +5452,7 @@ "@npmcli/map-workspaces", "@npmcli/package-json", "@npmcli/promise-spawn", + "@npmcli/redact", "@npmcli/run-script", "@sigstore/tuf", "abbrev", @@ -5460,8 +5461,6 @@ "chalk", "ci-info", "cli-columns", - "cli-table3", - "columnify", "fastest-levenshtein", "fs-minipass", "glob", @@ -5497,7 +5496,6 @@ "npm-profile", "npm-registry-fetch", "npm-user-validate", - "npmlog", "p-map", "pacote", "parse-conflict-json", @@ -5522,66 +5520,64 @@ "@npmcli/arborist": "^7.2.1", "@npmcli/config": "^8.0.2", "@npmcli/fs": "^3.1.0", - "@npmcli/map-workspaces": "^3.0.4", - "@npmcli/package-json": "^5.0.0", + "@npmcli/map-workspaces": "^3.0.6", + "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.1", - "@npmcli/run-script": "^7.0.4", - "@sigstore/tuf": "^2.3.1", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", + "@sigstore/tuf": "^2.3.2", "abbrev": "^2.0.0", "archy": "~1.0.0", "cacache": "^18.0.2", "chalk": "^5.3.0", "ci-info": "^4.0.0", "cli-columns": "^4.0.0", - "cli-table3": "^0.6.3", - "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.3.10", + "glob": "^10.3.12", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.1", - "ini": "^4.1.1", - "init-package-json": "^6.0.0", - "is-cidr": "^5.0.3", + "ini": "^4.1.2", + "init-package-json": "^6.0.2", + "is-cidr": "^5.0.5", "json-parse-even-better-errors": "^3.0.1", "libnpmaccess": "^8.0.1", "libnpmdiff": "^6.0.3", - "libnpmexec": "^7.0.4", + "libnpmexec": "^8.0.0", "libnpmfund": "^5.0.1", "libnpmhook": "^10.0.0", "libnpmorg": "^6.0.1", - "libnpmpack": "^6.0.3", + "libnpmpack": "^7.0.0", "libnpmpublish": "^9.0.2", "libnpmsearch": "^7.0.0", "libnpmteam": "^6.0.0", - "libnpmversion": "^5.0.1", - "make-fetch-happen": "^13.0.0", - "minimatch": "^9.0.3", + "libnpmversion": "^6.0.0", + "make-fetch-happen": "^13.0.1", + "minimatch": "^9.0.4", "minipass": "^7.0.4", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^10.0.1", + "node-gyp": "^10.1.0", "nopt": "^7.2.0", "normalize-package-data": "^6.0.0", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.3.0", - "npm-package-arg": "^11.0.1", + "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", - "npm-profile": "^9.0.0", - "npm-registry-fetch": "^16.1.0", + "npm-profile": "^9.0.2", + "npm-registry-fetch": "^17.0.0", "npm-user-validate": "^2.0.0", - "npmlog": "^7.0.1", "p-map": "^4.0.0", - "pacote": "^17.0.6", + "pacote": "^18.0.3", "parse-conflict-json": "^3.0.1", - "proc-log": "^3.0.0", + "proc-log": "^4.2.0", "qrcode-terminal": "^0.12.0", - "read": "^2.1.0", + "read": "^3.0.1", "semver": "^7.6.0", - "spdx-expression-parse": "^3.0.1", + "spdx-expression-parse": "^4.0.0", "ssri": "^10.0.5", "supports-color": "^9.4.0", - "tar": "^6.2.0", + "tar": "^6.2.1", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", @@ -5609,16 +5605,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/@colors/colors": { - "version": "1.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/npm/node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -5693,7 +5679,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/agent": { - "version": "2.2.1", + "version": "2.2.2", "dev": true, "inBundle": true, "license": "ISC", @@ -5702,44 +5688,45 @@ "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" + "socks-proxy-agent": "^8.0.3" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "7.4.0", + "version": "7.5.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^3.1.0", - "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/installed-package-contents": "^2.1.0", "@npmcli/map-workspaces": "^3.0.2", - "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/metavuln-calculator": "^7.1.0", "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.0.0", + "@npmcli/package-json": "^5.1.0", "@npmcli/query": "^3.1.0", - "@npmcli/run-script": "^7.0.2", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", "bin-links": "^4.0.1", "cacache": "^18.0.0", "common-ancestor-path": "^1.0.1", "hosted-git-info": "^7.0.1", "json-parse-even-better-errors": "^3.0.0", "json-stringify-nice": "^1.1.4", - "minimatch": "^9.0.0", + "minimatch": "^9.0.4", "nopt": "^7.0.0", "npm-install-checks": "^6.2.0", - "npm-package-arg": "^11.0.1", + "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "npmlog": "^7.0.1", - "pacote": "^17.0.4", + "npm-registry-fetch": "^17.0.0", + "pacote": "^18.0.1", "parse-conflict-json": "^3.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.2.0", + "proggy": "^2.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "read-package-json-fast": "^3.0.2", @@ -5756,16 +5743,16 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "8.2.0", + "version": "8.3.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", "ci-info": "^4.0.0", - "ini": "^4.1.0", + "ini": "^4.1.2", "nopt": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.2.0", "read-package-json-fast": "^3.0.2", "semver": "^7.3.5", "walk-up-path": "^3.0.1" @@ -5777,7 +5764,6 @@ "node_modules/npm/node_modules/@npmcli/disparity-colors": { "version": "3.0.0", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "ansi-styles": "^4.3.0" @@ -5789,7 +5775,6 @@ "node_modules/npm/node_modules/@npmcli/disparity-colors/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5814,7 +5799,7 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "5.0.4", + "version": "5.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -5822,7 +5807,7 @@ "@npmcli/promise-spawn": "^7.0.0", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", @@ -5833,7 +5818,7 @@ } }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", + "version": "2.1.0", "dev": true, "inBundle": true, "license": "ISC", @@ -5842,14 +5827,14 @@ "npm-normalize-package-bin": "^3.0.0" }, "bin": { - "installed-package-contents": "lib/index.js" + "installed-package-contents": "bin/index.js" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "3.0.4", + "version": "3.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -5864,14 +5849,15 @@ } }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "7.0.0", + "version": "7.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "cacache": "^18.0.0", "json-parse-even-better-errors": "^3.0.0", - "pacote": "^17.0.0", + "pacote": "^18.0.0", + "proc-log": "^4.1.0", "semver": "^7.3.5" }, "engines": { @@ -5897,7 +5883,7 @@ } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "5.0.0", + "version": "5.1.0", "dev": true, "inBundle": true, "license": "ISC", @@ -5907,7 +5893,7 @@ "hosted-git-info": "^7.0.0", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^6.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "semver": "^7.5.3" }, "engines": { @@ -5938,8 +5924,17 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "7.0.4", + "version": "8.1.0", "dev": true, "inBundle": true, "license": "ISC", @@ -5948,6 +5943,7 @@ "@npmcli/package-json": "^5.0.0", "@npmcli/promise-spawn": "^7.0.0", "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", "which": "^4.0.0" }, "engines": { @@ -5965,19 +5961,19 @@ } }, "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "2.2.0", + "version": "2.3.1", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.3.0" + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@sigstore/core": { - "version": "1.0.0", + "version": "1.1.0", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -5986,23 +5982,23 @@ } }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.3.0", + "version": "0.3.1", "dev": true, "inBundle": true, "license": "Apache-2.0", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@sigstore/sign": { - "version": "2.2.3", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.2.0", + "@sigstore/bundle": "^2.3.0", "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/protobuf-specs": "^0.3.1", "make-fetch-happen": "^13.0.0" }, "engines": { @@ -6010,7 +6006,7 @@ } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "2.3.1", + "version": "2.3.2", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -6023,14 +6019,14 @@ } }, "node_modules/npm/node_modules/@sigstore/verify": { - "version": "1.1.0", + "version": "1.2.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.2.0", - "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.0" + "@sigstore/bundle": "^2.3.1", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -6068,7 +6064,7 @@ } }, "node_modules/npm/node_modules/agent-base": { - "version": "7.1.0", + "version": "7.1.1", "dev": true, "inBundle": true, "license": "MIT", @@ -6128,7 +6124,6 @@ "node_modules/npm/node_modules/are-we-there-yet": { "version": "4.0.2", "dev": true, - "inBundle": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -6156,12 +6151,15 @@ } }, "node_modules/npm/node_modules/binary-extensions": { - "version": "2.2.0", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm/node_modules/brace-expansion": { @@ -6174,7 +6172,7 @@ } }, "node_modules/npm/node_modules/builtins": { - "version": "5.0.1", + "version": "5.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -6242,7 +6240,7 @@ } }, "node_modules/npm/node_modules/cidr-regex": { - "version": "4.0.3", + "version": "4.0.5", "dev": true, "inBundle": true, "license": "BSD-2-Clause", @@ -6275,30 +6273,6 @@ "node": ">= 10" } }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/npm/node_modules/clone": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, "node_modules/npm/node_modules/cmd-shim": { "version": "6.0.2", "dev": true, @@ -6329,25 +6303,11 @@ "node_modules/npm/node_modules/color-support": { "version": "1.1.3", "dev": true, - "inBundle": true, "license": "ISC", "bin": { "color-support": "bin.js" } }, - "node_modules/npm/node_modules/columnify": { - "version": "1.6.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", "dev": true, @@ -6357,7 +6317,6 @@ "node_modules/npm/node_modules/console-control-strings": { "version": "1.1.0", "dev": true, - "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/cross-spawn": { @@ -6424,18 +6383,6 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/defaults": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/npm/node_modules/diff": { "version": "5.2.0", "dev": true, @@ -6537,7 +6484,6 @@ "node_modules/npm/node_modules/gauge": { "version": "5.0.1", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^1.0.3 || ^2.0.0", @@ -6554,16 +6500,16 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "10.3.10", + "version": "10.3.12", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -6584,11 +6530,10 @@ "node_modules/npm/node_modules/has-unicode": { "version": "2.0.1", "dev": true, - "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/hasown": { - "version": "2.0.1", + "version": "2.0.2", "dev": true, "inBundle": true, "license": "MIT", @@ -6687,7 +6632,7 @@ } }, "node_modules/npm/node_modules/ini": { - "version": "4.1.1", + "version": "4.1.2", "dev": true, "inBundle": true, "license": "ISC", @@ -6696,15 +6641,15 @@ } }, "node_modules/npm/node_modules/init-package-json": { - "version": "6.0.0", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { + "@npmcli/package-json": "^5.0.0", "npm-package-arg": "^11.0.0", "promzard": "^1.0.0", - "read": "^2.0.0", - "read-package-json": "^7.0.0", + "read": "^3.0.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^5.0.0" @@ -6726,12 +6671,6 @@ "node": ">= 12" } }, - "node_modules/npm/node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "BSD-3-Clause" - }, "node_modules/npm/node_modules/ip-regex": { "version": "5.0.0", "dev": true, @@ -6745,12 +6684,12 @@ } }, "node_modules/npm/node_modules/is-cidr": { - "version": "5.0.3", + "version": "5.0.5", "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { - "cidr-regex": "4.0.3" + "cidr-regex": "^4.0.4" }, "engines": { "node": ">=14" @@ -6853,52 +6792,50 @@ "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { - "version": "8.0.2", + "version": "8.0.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-package-arg": "^11.0.1", - "npm-registry-fetch": "^16.0.0" + "npm-package-arg": "^11.0.2", + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "6.0.7", + "version": "6.1.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/disparity-colors": "^3.0.0", - "@npmcli/installed-package-contents": "^2.0.2", - "binary-extensions": "^2.2.0", + "@npmcli/installed-package-contents": "^2.1.0", + "binary-extensions": "^2.3.0", "diff": "^5.1.0", - "minimatch": "^9.0.0", - "npm-package-arg": "^11.0.1", - "pacote": "^17.0.4", - "tar": "^6.2.0" + "minimatch": "^9.0.4", + "npm-package-arg": "^11.0.2", + "pacote": "^18.0.1", + "tar": "^6.2.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "7.0.8", + "version": "8.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/run-script": "^7.0.2", + "@npmcli/run-script": "^8.1.0", "ci-info": "^4.0.0", - "npm-package-arg": "^11.0.1", - "npmlog": "^7.0.1", - "pacote": "^17.0.4", - "proc-log": "^3.0.0", - "read": "^2.0.0", + "npm-package-arg": "^11.0.2", + "pacote": "^18.0.1", + "proc-log": "^4.2.0", + "read": "^3.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "walk-up-path": "^3.0.1" @@ -6908,7 +6845,7 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "5.0.5", + "version": "5.0.9", "dev": true, "inBundle": true, "license": "ISC", @@ -6920,57 +6857,57 @@ } }, "node_modules/npm/node_modules/libnpmhook": { - "version": "10.0.1", + "version": "10.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmorg": { - "version": "6.0.2", + "version": "6.0.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "6.0.7", + "version": "7.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/run-script": "^7.0.2", - "npm-package-arg": "^11.0.1", - "pacote": "^17.0.4" + "@npmcli/run-script": "^8.1.0", + "npm-package-arg": "^11.0.2", + "pacote": "^18.0.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "9.0.4", + "version": "9.0.7", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "ci-info": "^4.0.0", "normalize-package-data": "^6.0.0", - "npm-package-arg": "^11.0.1", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "npm-package-arg": "^11.0.2", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.2.0", "semver": "^7.3.7", "sigstore": "^2.2.0", "ssri": "^10.0.5" @@ -6980,40 +6917,40 @@ } }, "node_modules/npm/node_modules/libnpmsearch": { - "version": "7.0.1", + "version": "7.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmteam": { - "version": "6.0.1", + "version": "6.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmversion": { - "version": "5.0.2", + "version": "6.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.3", - "@npmcli/run-script": "^7.0.2", + "@npmcli/git": "^5.0.6", + "@npmcli/run-script": "^8.1.0", "json-parse-even-better-errors": "^3.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.2.0", "semver": "^7.3.7" }, "engines": { @@ -7021,7 +6958,7 @@ } }, "node_modules/npm/node_modules/lru-cache": { - "version": "10.2.0", + "version": "10.2.2", "dev": true, "inBundle": true, "license": "ISC", @@ -7030,7 +6967,7 @@ } }, "node_modules/npm/node_modules/make-fetch-happen": { - "version": "13.0.0", + "version": "13.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -7044,6 +6981,7 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", + "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" }, @@ -7052,7 +6990,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "9.0.3", + "version": "9.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -7260,7 +7198,7 @@ } }, "node_modules/npm/node_modules/node-gyp": { - "version": "10.0.1", + "version": "10.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -7283,6 +7221,15 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/npm/node_modules/node-gyp/node_modules/proc-log": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/npm/node_modules/nopt": { "version": "7.2.0", "dev": true, @@ -7356,13 +7303,13 @@ } }, "node_modules/npm/node_modules/npm-package-arg": { - "version": "11.0.1", + "version": "11.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" }, @@ -7398,31 +7345,32 @@ } }, "node_modules/npm/node_modules/npm-profile": { - "version": "9.0.0", + "version": "9.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0" + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "16.1.0", + "version": "17.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { + "@npmcli/redact": "^2.0.0", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", - "proc-log": "^3.0.0" + "proc-log": "^4.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -7440,7 +7388,6 @@ "node_modules/npm/node_modules/npmlog": { "version": "7.0.1", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "are-we-there-yet": "^4.0.0", @@ -7468,26 +7415,25 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "17.0.6", + "version": "18.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", + "@npmcli/run-script": "^8.0.0", "cacache": "^18.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^11.0.0", "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", "promise-retry": "^2.0.1", - "read-package-json": "^7.0.0", - "read-package-json-fast": "^3.0.0", "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" @@ -7523,12 +7469,12 @@ } }, "node_modules/npm/node_modules/path-scurry": { - "version": "1.10.1", + "version": "1.10.2", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -7539,7 +7485,7 @@ } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.0.15", + "version": "6.0.16", "dev": true, "inBundle": true, "license": "MIT", @@ -7552,7 +7498,16 @@ } }, "node_modules/npm/node_modules/proc-log": { - "version": "3.0.0", + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "2.0.0", "dev": true, "inBundle": true, "license": "ISC", @@ -7598,12 +7553,12 @@ } }, "node_modules/npm/node_modules/promzard": { - "version": "1.0.0", + "version": "1.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "read": "^2.0.0" + "read": "^3.0.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -7618,12 +7573,12 @@ } }, "node_modules/npm/node_modules/read": { - "version": "2.1.0", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "mute-stream": "~1.0.0" + "mute-stream": "^1.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -7641,7 +7596,6 @@ "node_modules/npm/node_modules/read-package-json": { "version": "7.0.0", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "glob": "^10.2.2", @@ -7712,7 +7666,6 @@ "node_modules/npm/node_modules/set-blocking": { "version": "2.0.0", "dev": true, - "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/shebang-command": { @@ -7749,17 +7702,17 @@ } }, "node_modules/npm/node_modules/sigstore": { - "version": "2.2.2", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.2.0", + "@sigstore/bundle": "^2.3.1", "@sigstore/core": "^1.0.0", - "@sigstore/protobuf-specs": "^0.3.0", - "@sigstore/sign": "^2.2.3", + "@sigstore/protobuf-specs": "^0.3.1", + "@sigstore/sign": "^2.3.0", "@sigstore/tuf": "^2.3.1", - "@sigstore/verify": "^1.1.0" + "@sigstore/verify": "^1.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -7776,7 +7729,7 @@ } }, "node_modules/npm/node_modules/socks": { - "version": "2.8.0", + "version": "2.8.3", "dev": true, "inBundle": true, "license": "MIT", @@ -7785,17 +7738,17 @@ "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 16.0.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.2", + "version": "8.0.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", "socks": "^2.7.1" }, @@ -7813,6 +7766,16 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/npm/node_modules/spdx-exceptions": { "version": "2.5.0", "dev": true, @@ -7820,7 +7783,7 @@ "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.1", + "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", @@ -7835,6 +7798,12 @@ "inBundle": true, "license": "CC0-1.0" }, + "node_modules/npm/node_modules/sprintf-js": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause" + }, "node_modules/npm/node_modules/ssri": { "version": "10.0.5", "dev": true, @@ -7914,7 +7883,7 @@ } }, "node_modules/npm/node_modules/tar": { - "version": "6.2.0", + "version": "6.2.1", "dev": true, "inBundle": true, "license": "ISC", @@ -8038,6 +8007,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/npm/node_modules/validate-npm-package-name": { "version": "5.0.0", "dev": true, @@ -8056,15 +8035,6 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npm/node_modules/wcwidth": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, "node_modules/npm/node_modules/which": { "version": "4.0.0", "dev": true, @@ -8092,7 +8062,6 @@ "node_modules/npm/node_modules/wide-align": { "version": "1.1.5", "dev": true, - "inBundle": true, "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" diff --git a/src/Instance.ts b/src/Instance.ts index eb460e0642..9019301731 100644 --- a/src/Instance.ts +++ b/src/Instance.ts @@ -6,7 +6,8 @@ import { _Renderer } from './Renderer.ts'; import { _Tokenizer } from './Tokenizer.ts'; import { _TextRenderer } from './TextRenderer.ts'; import { - escape + escape, + unescape } from './helpers.ts'; import type { MarkedExtension, MarkedOptions } from './MarkedOptions.ts'; import type { Token, Tokens, TokensList } from './Tokens.ts'; @@ -146,15 +147,19 @@ export class Marked { if (!(prop in renderer)) { throw new Error(`renderer '${prop}' does not exist`); } - if (prop === 'options') { + if (['options', 'parser'].includes(prop)) { // ignore options property continue; } - const rendererProp = prop as Exclude; - const rendererFunc = pack.renderer[rendererProp] as GenericRendererFunction; + const rendererProp = prop as Exclude; + let rendererFunc = pack.renderer[rendererProp] as GenericRendererFunction; const prevRenderer = renderer[rendererProp] as GenericRendererFunction; // Replace renderer with func to run extension, but fall back if false renderer[rendererProp] = (...args: unknown[]) => { + if (!pack.useNewRenderer) { + // TODO: Remove this in next major version + rendererFunc = this.#convertRendererFunction(rendererFunc, rendererProp, renderer) as GenericRendererFunction; + } let ret = rendererFunc.apply(renderer, args); if (ret === false) { ret = prevRenderer.apply(renderer, args); @@ -250,6 +255,250 @@ export class Marked { return this; } + // TODO: Remove this in next major release + #convertRendererFunction(func: GenericRendererFunction, prop: string, renderer: _Renderer) { + switch (prop) { + case 'heading': + return function(token: Tokens.Heading) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func( + renderer.parser.parseInline(token.tokens), + token.depth, + unescape(renderer.parser.parseInline(token.tokens, renderer.parser.textRenderer)) + ); + }; + case 'code': + return function(token: Tokens.Code) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func( + token.text, + token.lang, + !!token.escaped + ); + }; + case 'table': + return function(this: _Renderer, token: Tokens.Table) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + let header = ''; + // header + let cell = ''; + for (let j = 0; j < token.header.length; j++) { + cell += this.tablecell( + { + text: token.header[j].text, + tokens: token.header[j].tokens, + header: true, + align: token.align[j] + } + ); + } + header += this.tablerow({ text: cell }); + + let body = ''; + for (let j = 0; j < token.rows.length; j++) { + const row = token.rows[j]; + + cell = ''; + for (let k = 0; k < row.length; k++) { + cell += this.tablecell( + { + text: row[k].text, + tokens: row[k].tokens, + header: false, + align: token.align[k] + } + ); + } + + body += this.tablerow({ text: cell }); + } + + return func(header, body); + }; + case 'blockquote': + return function(this: _Renderer, token: Tokens.Blockquote) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + const body = this.parser.parse(token.tokens); + return func(body); + }; + case 'list': + return function(this: _Renderer, token: Tokens.List) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + const ordered = token.ordered; + const start = token.start; + const loose = token.loose; + + let body = ''; + for (let j = 0; j < token.items.length; j++) { + const item = token.items[j]; + const checked = item.checked; + const task = item.task; + + let itemBody = ''; + if (item.task) { + const checkbox = this.checkbox({ checked: !!checked }); + if (loose) { + if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') { + item.tokens[0].text = checkbox + ' ' + item.tokens[0].text; + if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') { + item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text; + } + } else { + item.tokens.unshift({ + type: 'text', + text: checkbox + ' ' + } as Tokens.Text); + } + } else { + itemBody += checkbox + ' '; + } + } + + itemBody += this.parser.parse(item.tokens, loose); + body += this.listitem({ + type: 'list_item', + raw: itemBody, + text: itemBody, + task, + checked: !!checked, + loose, + tokens: item.tokens + }); + } + + return func(body, ordered, start); + }; + case 'html': + return function(token: Tokens.HTML) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(token.text, token.block); + }; + case 'paragraph': + return function(this: _Renderer, token: Tokens.Paragraph) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(this.parser.parseInline(token.tokens)); + }; + case 'escape': + return function(token: Tokens.Escape) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(token.text); + }; + case 'link': + return function(this: _Renderer, token: Tokens.Link) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(token.href, token.title, this.parser.parseInline(token.tokens)); + }; + case 'image': + return function(token: Tokens.Image) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(token.href, token.title, token.text); + }; + case 'strong': + return function(this: _Renderer, token: Tokens.Strong) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(this.parser.parseInline(token.tokens)); + }; + case 'em': + return function(this: _Renderer, token: Tokens.Em) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(this.parser.parseInline(token.tokens)); + }; + case 'codespan': + return function(token: Tokens.Codespan) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(token.text); + }; + case 'del': + return function(this: _Renderer, token: Tokens.Del) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(this.parser.parseInline(token.tokens)); + }; + case 'text': + return function(token: Tokens.Text) { + if (!token.type || token.type !== prop) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + return func.apply(this, arguments); + } + + return func(token.text); + }; + default: + // do nothing + } + return func; + } + setOptions(opt: MarkedOptions) { this.defaults = { ...this.defaults, ...opt }; return this; diff --git a/src/MarkedOptions.ts b/src/MarkedOptions.ts index 78754f23fe..8b0d0ea780 100644 --- a/src/MarkedOptions.ts +++ b/src/MarkedOptions.ts @@ -39,7 +39,7 @@ type HooksObject = { [K in keyof HooksApi]?: (...args: Parameters) => ReturnType | Promise> }; -type RendererApi = Omit<_Renderer, 'constructor' | 'options'>; +type RendererApi = Omit<_Renderer, 'constructor' | 'options' | 'parser'>; type RendererObject = { [K in keyof RendererApi]?: (...args: Parameters) => ReturnType | false }; @@ -109,9 +109,15 @@ export interface MarkedExtension { * The return value of the function is ignored. */ walkTokens?: ((token: Token) => void | Promise) | undefined | null; + + /** + * Use the new renderer that accepts an object instead of individual parameters. + * This option will be removed and default to true in the next major version. + */ + useNewRenderer?: boolean | undefined; } -export interface MarkedOptions extends Omit { +export interface MarkedOptions extends Omit { /** * Hooks are methods that hook into some part of marked. */ diff --git a/src/Parser.ts b/src/Parser.ts index d1be35f80f..dfac9b6d54 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -1,10 +1,7 @@ import { _Renderer } from './Renderer.ts'; import { _TextRenderer } from './TextRenderer.ts'; import { _defaults } from './defaults.ts'; -import { - unescape -} from './helpers.ts'; -import type { Token, Tokens } from './Tokens.ts'; +import type { MarkedToken, Token, Tokens } from './Tokens.ts'; import type { MarkedOptions } from './MarkedOptions.ts'; /** @@ -19,6 +16,7 @@ export class _Parser { this.options.renderer = this.options.renderer || new _Renderer(); this.renderer = this.options.renderer; this.renderer.options = this.options; + this.renderer.parser = this; this.textRenderer = new _TextRenderer(); } @@ -45,11 +43,11 @@ export class _Parser { let out = ''; for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; + const anyToken = tokens[i]; // Run any renderer extensions - if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) { - const genericToken = token as Tokens.Generic; + if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) { + const genericToken = anyToken as Tokens.Generic; const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken); if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(genericToken.type)) { out += ret || ''; @@ -57,123 +55,62 @@ export class _Parser { } } + const token = anyToken as MarkedToken; + switch (token.type) { case 'space': { + out += this.renderer.space(token); continue; } case 'hr': { - out += this.renderer.hr(); + out += this.renderer.hr(token); continue; } case 'heading': { - const headingToken = token as Tokens.Heading; - out += this.renderer.heading( - this.parseInline(headingToken.tokens), - headingToken.depth, - unescape(this.parseInline(headingToken.tokens, this.textRenderer))); + out += this.renderer.heading(token); continue; } case 'code': { - const codeToken = token as Tokens.Code; - out += this.renderer.code(codeToken.text, - codeToken.lang, - !!codeToken.escaped); + out += this.renderer.code(token); continue; } case 'table': { - const tableToken = token as Tokens.Table; - let header = ''; - - // header - let cell = ''; - for (let j = 0; j < tableToken.header.length; j++) { - cell += this.renderer.tablecell( - this.parseInline(tableToken.header[j].tokens), - { header: true, align: tableToken.align[j] } - ); - } - header += this.renderer.tablerow(cell); - - let body = ''; - for (let j = 0; j < tableToken.rows.length; j++) { - const row = tableToken.rows[j]; - - cell = ''; - for (let k = 0; k < row.length; k++) { - cell += this.renderer.tablecell( - this.parseInline(row[k].tokens), - { header: false, align: tableToken.align[k] } - ); - } - - body += this.renderer.tablerow(cell); - } - out += this.renderer.table(header, body); + out += this.renderer.table(token); continue; } case 'blockquote': { - const blockquoteToken = token as Tokens.Blockquote; - const body = this.parse(blockquoteToken.tokens); - out += this.renderer.blockquote(body); + out += this.renderer.blockquote(token); continue; } case 'list': { - const listToken = token as Tokens.List; - const ordered = listToken.ordered; - const start = listToken.start; - const loose = listToken.loose; - - let body = ''; - for (let j = 0; j < listToken.items.length; j++) { - const item = listToken.items[j]; - const checked = item.checked; - const task = item.task; - - let itemBody = ''; - if (item.task) { - const checkbox = this.renderer.checkbox(!!checked); - if (loose) { - if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') { - item.tokens[0].text = checkbox + ' ' + item.tokens[0].text; - if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') { - item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text; - } - } else { - item.tokens.unshift({ - type: 'text', - text: checkbox + ' ' - } as Tokens.Text); - } - } else { - itemBody += checkbox + ' '; - } - } - - itemBody += this.parse(item.tokens, loose); - body += this.renderer.listitem(itemBody, task, !!checked); - } - - out += this.renderer.list(body, ordered, start); + out += this.renderer.list(token); continue; } case 'html': { - const htmlToken = token as Tokens.HTML; - out += this.renderer.html(htmlToken.text, htmlToken.block); + out += this.renderer.html(token); continue; } case 'paragraph': { - const paragraphToken = token as Tokens.Paragraph; - out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens)); + out += this.renderer.paragraph(token); continue; } case 'text': { - let textToken = token as Tokens.Text; - let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text; + let textToken = token; + let body = this.renderer.text(textToken); while (i + 1 < tokens.length && tokens[i + 1].type === 'text') { - textToken = tokens[++i] as Tokens.Text; - body += '\n' + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text); + textToken = tokens[++i] as Tokens.Text | Tokens.Tag; + body += '\n' + this.renderer.text(textToken); + } + if (top) { + out += this.renderer.paragraph({ + type: 'paragraph', + raw: body, + text: body, + tokens: [{ type: 'text', raw: body, text: body }] + }); + } else { + out += body; } - out += top ? this.renderer.paragraph(body) : body; continue; } @@ -200,65 +137,58 @@ export class _Parser { let out = ''; for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; + const anyToken = tokens[i]; // Run any renderer extensions - if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) { - const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token); - if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) { + if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[anyToken.type]) { + const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken); + if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(anyToken.type)) { out += ret || ''; continue; } } + const token = anyToken as MarkedToken; + switch (token.type) { case 'escape': { - const escapeToken = token as Tokens.Escape; - out += renderer.text(escapeToken.text); + out += renderer.text(token); break; } case 'html': { - const tagToken = token as Tokens.Tag; - out += renderer.html(tagToken.text); + out += renderer.html(token); break; } case 'link': { - const linkToken = token as Tokens.Link; - out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer)); + out += renderer.link(token); break; } case 'image': { - const imageToken = token as Tokens.Image; - out += renderer.image(imageToken.href, imageToken.title, imageToken.text); + out += renderer.image(token); break; } case 'strong': { - const strongToken = token as Tokens.Strong; - out += renderer.strong(this.parseInline(strongToken.tokens, renderer)); + out += renderer.strong(token); break; } case 'em': { - const emToken = token as Tokens.Em; - out += renderer.em(this.parseInline(emToken.tokens, renderer)); + out += renderer.em(token); break; } case 'codespan': { - const codespanToken = token as Tokens.Codespan; - out += renderer.codespan(codespanToken.text); + out += renderer.codespan(token); break; } case 'br': { - out += renderer.br(); + out += renderer.br(token); break; } case 'del': { - const delToken = token as Tokens.Del; - out += renderer.del(this.parseInline(delToken.tokens, renderer)); + out += renderer.del(token); break; } case 'text': { - const textToken = token as Tokens.Text; - out += renderer.text(textToken.text); + out += renderer.text(token); break; } default: { diff --git a/src/Renderer.ts b/src/Renderer.ts index e00868c977..b790803a90 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -4,72 +4,131 @@ import { escape } from './helpers.ts'; import type { MarkedOptions } from './MarkedOptions.ts'; +import type { Tokens } from './Tokens.ts'; +import type { _Parser } from './Parser.ts'; /** * Renderer */ export class _Renderer { options: MarkedOptions; + parser!: _Parser; // set by the parser constructor(options?: MarkedOptions) { this.options = options || _defaults; } - code(code: string, infostring: string | undefined, escaped: boolean): string { - const lang = (infostring || '').match(/^\S*/)?.[0]; + space(token: Tokens.Space): string { + return ''; + } + + code({ text, lang, escaped }: Tokens.Code): string { + const langString = (lang || '').match(/^\S*/)?.[0]; - code = code.replace(/\n$/, '') + '\n'; + const code = text.replace(/\n$/, '') + '\n'; - if (!lang) { + if (!langString) { return '
'
         + (escaped ? code : escape(code, true))
         + '
\n'; } return '
'
       + (escaped ? code : escape(code, true))
       + '
\n'; } - blockquote(quote: string): string { - return `
\n${quote}
\n`; + blockquote({ tokens }: Tokens.Blockquote): string { + const body = this.parser.parse(tokens); + return `
\n${body}
\n`; } - html(html: string, block?: boolean) : string { - return html; + html({ text }: Tokens.HTML | Tokens.Tag) : string { + return text; } - heading(text: string, level: number, raw: string): string { - // ignore IDs - return `${text}\n`; + heading({ tokens, depth }: Tokens.Heading): string { + return `${this.parser.parseInline(tokens)}\n`; } - hr(): string { + hr(token: Tokens.Hr): string { return '
\n'; } - list(body: string, ordered: boolean, start: number | ''): string { + list(token: Tokens.List): string { + const ordered = token.ordered; + const start = token.start; + + let body = ''; + for (let j = 0; j < token.items.length; j++) { + const item = token.items[j]; + body += this.listitem(item); + } + const type = ordered ? 'ol' : 'ul'; - const startatt = (ordered && start !== 1) ? (' start="' + start + '"') : ''; - return '<' + type + startatt + '>\n' + body + '\n'; - } + const startAttr = (ordered && start !== 1) ? (' start="' + start + '"') : ''; + return '<' + type + startAttr + '>\n' + body + '\n'; + } + + listitem(item: Tokens.ListItem): string { + let itemBody = ''; + if (item.task) { + const checkbox = this.checkbox({ checked: !!item.checked }); + if (item.loose) { + if (item.tokens.length > 0 && item.tokens[0].type === 'paragraph') { + item.tokens[0].text = checkbox + ' ' + item.tokens[0].text; + if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') { + item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text; + } + } else { + item.tokens.unshift({ + type: 'text', + raw: checkbox + ' ', + text: checkbox + ' ' + }); + } + } else { + itemBody += checkbox + ' '; + } + } - listitem(text: string, task: boolean, checked: boolean): string { - return `
  • ${text}
  • \n`; + itemBody += this.parser.parse(item.tokens, !!item.loose); + + return `
  • ${itemBody}
  • \n`; } - checkbox(checked: boolean): string { + checkbox({ checked }: Tokens.Checkbox): string { return ''; } - paragraph(text: string): string { - return `

    ${text}

    \n`; + paragraph({ tokens }: Tokens.Paragraph): string { + return `

    ${this.parser.parseInline(tokens)}

    \n`; } - table(header: string, body: string): string { + table(token: Tokens.Table): string { + let header = ''; + + // header + let cell = ''; + for (let j = 0; j < token.header.length; j++) { + cell += this.tablecell(token.header[j]); + } + header += this.tablerow({ text: cell }); + + let body = ''; + for (let j = 0; j < token.rows.length; j++) { + const row = token.rows[j]; + + cell = ''; + for (let k = 0; k < row.length; k++) { + cell += this.tablecell(row[k]); + } + + body += this.tablerow({ text: cell }); + } if (body) body = `${body}`; return '\n' @@ -80,17 +139,15 @@ export class _Renderer { + '
    \n'; } - tablerow(content: string): string { - return `\n${content}\n`; + tablerow({ text }: Tokens.TableRow): string { + return `\n${text}\n`; } - tablecell(content: string, flags: { - header: boolean; - align: 'center' | 'left' | 'right' | null; - }): string { - const type = flags.header ? 'th' : 'td'; - const tag = flags.align - ? `<${type} align="${flags.align}">` + tablecell(token: Tokens.TableCell): string { + const content = this.parser.parseInline(token.tokens); + const type = token.header ? 'th' : 'td'; + const tag = token.align + ? `<${type} align="${token.align}">` : `<${type}>`; return tag + content + `\n`; } @@ -98,27 +155,28 @@ export class _Renderer { /** * span level renderer */ - strong(text: string): string { - return `${text}`; + strong({ tokens }: Tokens.Strong): string { + return `${this.parser.parseInline(tokens)}`; } - em(text: string): string { - return `${text}`; + em({ tokens }: Tokens.Em): string { + return `${this.parser.parseInline(tokens)}`; } - codespan(text: string): string { + codespan({ text }: Tokens.Codespan): string { return `${text}`; } - br(): string { + br(token: Tokens.Br): string { return '
    '; } - del(text: string): string { - return `${text}`; + del({ tokens }: Tokens.Del): string { + return `${this.parser.parseInline(tokens)}`; } - link(href: string, title: string | null | undefined, text: string): string { + link({ href, title, tokens }: Tokens.Link): string { + const text = this.parser.parseInline(tokens); const cleanHref = cleanUrl(href); if (cleanHref === null) { return text; @@ -132,7 +190,7 @@ export class _Renderer { return out; } - image(href: string, title: string | null, text: string): string { + image({ href, title, text }: Tokens.Image): string { const cleanHref = cleanUrl(href); if (cleanHref === null) { return text; @@ -147,7 +205,7 @@ export class _Renderer { return out; } - text(text: string) : string { - return text; + text(token: Tokens.Text | Tokens.Escape | Tokens.Tag) : string { + return 'tokens' in token && token.tokens ? this.parser.parseInline(token.tokens) : token.text; } } diff --git a/src/TextRenderer.ts b/src/TextRenderer.ts index 038b6db031..a83b754811 100644 --- a/src/TextRenderer.ts +++ b/src/TextRenderer.ts @@ -1,38 +1,40 @@ +import type { Tokens } from './Tokens.ts'; + /** * TextRenderer * returns only the textual part of the token */ export class _TextRenderer { // no need for block level renderers - strong(text: string) { + strong({ text }: Tokens.Strong) { return text; } - em(text: string) { + em({ text }: Tokens.Em) { return text; } - codespan(text: string) { + codespan({ text }: Tokens.Codespan) { return text; } - del(text: string) { + del({ text }: Tokens.Del) { return text; } - html(text: string) { + html({ text }: Tokens.HTML | Tokens.Tag) { return text; } - text(text: string) { + text({ text }: Tokens.Text | Tokens.Escape | Tokens.Tag) { return text; } - link(href: string, title: string | null | undefined, text: string) { + link({ text }: Tokens.Link) { return '' + text; } - image(href: string, title: string | null, text: string) { + image({ text }: Tokens.Image) { return '' + text; } diff --git a/src/Tokenizer.ts b/src/Tokenizer.ts index 63156d7e82..4f520f7867 100644 --- a/src/Tokenizer.ts +++ b/src/Tokenizer.ts @@ -503,18 +503,22 @@ export class _Tokenizer { } } - for (const header of headers) { + for (let i = 0; i < headers.length; i++) { item.header.push({ - text: header, - tokens: this.lexer.inline(header) + text: headers[i], + tokens: this.lexer.inline(headers[i]), + header: true, + align: item.align[i] }); } for (const row of rows) { - item.rows.push(splitCells(row, item.header.length).map(cell => { + item.rows.push(splitCells(row, item.header.length).map((cell, i) => { return { text: cell, - tokens: this.lexer.inline(cell) + tokens: this.lexer.inline(cell), + header: false, + align: item.align[i] }; })); } diff --git a/src/Tokens.ts b/src/Tokens.ts index c5c846a557..1dd5a9ea3f 100644 --- a/src/Tokens.ts +++ b/src/Tokens.ts @@ -1,5 +1,6 @@ /* eslint-disable no-use-before-define */ -export type Token = ( + +export type MarkedToken = ( Tokens.Space | Tokens.Code | Tokens.Heading @@ -20,7 +21,10 @@ export type Token = ( | Tokens.Em | Tokens.Codespan | Tokens.Br - | Tokens.Del + | Tokens.Del); + +export type Token = ( + MarkedToken | Tokens.Generic); export namespace Tokens { @@ -54,9 +58,15 @@ export namespace Tokens { rows: TableCell[][]; } + export interface TableRow { + text: string; + } + export interface TableCell { text: string; tokens: Token[]; + header: boolean; + align: 'center' | 'left' | 'right' | null; } export interface Hr { @@ -90,6 +100,10 @@ export namespace Tokens { tokens: Token[]; } + export interface Checkbox { + checked: boolean; + } + export interface Paragraph { type: 'paragraph'; raw: string; diff --git a/test/types/marked.ts b/test/types/marked.ts index 8bf2997b2e..b8d373bbb3 100644 --- a/test/types/marked.ts +++ b/test/types/marked.ts @@ -64,6 +64,7 @@ console.log(marked.parseInline('9) I am using __markdown__.')); console.log(marked.parseInline('10) I am using __markdown__.', options)); const text = 'Something'; +const raw = 'Raw'; const tokens: TokensList = marked.lexer(text, options); console.log(marked.parser(tokens)); @@ -79,8 +80,8 @@ const re: Record>> = marked.Lexer. const lexerOptions: MarkedOptions = lexer.options; const renderer = new marked.Renderer(); -renderer.heading = (text, level, raw) => { - return text + level.toString(); +renderer.heading = ({ text, depth }) => { + return text + depth.toString(); }; renderer.hr = () => { return `
    \n`; @@ -90,31 +91,31 @@ renderer.checkbox = checked => { }; class ExtendedRenderer extends marked.Renderer { - code = (code: string, language: string | undefined, isEscaped: boolean): string => super.code(code, language, isEscaped); - blockquote = (quote: string): string => super.blockquote(quote); - html = (html: string): string => super.html(html); - heading = (text: string, level: 1 | 2 | 3 | 4 | 5 | 6, raw: string): string => super.heading(text, level, raw); - hr = (): string => super.hr(); - list = (body: string, ordered: boolean, start: number): string => super.list(body, ordered, start); - listitem = (text: string, task: boolean, checked: boolean): string => super.listitem(text, task, checked); - checkbox = (checked: boolean): string => super.checkbox(checked); - paragraph = (text: string): string => super.paragraph(text); - table = (header: string, body: string): string => super.table(header, body); - tablerow = (content: string): string => super.tablerow(content); - tablecell = (content: string, flags: { header: boolean; align: 'center' | 'left' | 'right' | null }): string => super.tablecell(content, flags); - strong = (text: string): string => super.strong(text); - em = (text: string): string => super.em(text); - codespan = (code: string): string => super.codespan(code); - br = (): string => super.br(); - del = (text: string): string => super.del(text); - link = (href: string, title: string, text: string): string => super.link(href, title, text); - image = (href: string, title: string, text: string): string => super.image(href, title, text); + code = ({ type, raw, text, codeBlockStyle, lang, escaped }: Tokens.Code): string => super.code({ type, raw, text, codeBlockStyle, lang, escaped }); + blockquote = ({ type, raw, text, tokens }: Tokens.Blockquote): string => super.blockquote({ type, raw, text, tokens }); + html = ({ type, raw, text, pre, block }: Tokens.HTML): string => super.html({ type, raw, text, pre, block }); + heading = ({ type, raw, text, depth, tokens }: Tokens.Heading): string => super.heading({ type, raw, text, depth, tokens }); + hr = ({ type, raw }: Tokens.Hr): string => super.hr({ type, raw }); + list = ({ type, raw, ordered, start, loose, items }: Tokens.List): string => super.list({ type, raw, ordered, start, loose, items}); + listitem = ({ type, raw, task, checked, loose, text, tokens }: Tokens.ListItem): string => super.listitem({ type, raw, task, checked, loose, text, tokens }); + checkbox = ({ checked }: Tokens.Checkbox): string => super.checkbox({ checked }); + paragraph = ({ type, raw, pre, text, tokens }: Tokens.Paragraph): string => super.paragraph({ type, raw, pre, text, tokens }); + table = ({ type, raw, align, header, rows }: Tokens.Table): string => super.table({ type, raw, align, header, rows }); + tablerow = ({ text }: Tokens.TableRow): string => super.tablerow({ text }); + tablecell = ({ text, tokens, header, align }: Tokens.TableCell): string => super.tablecell({ text, tokens, header, align }); + strong = ({ type, raw, text, tokens }: Tokens.Strong): string => super.strong({ type, raw, text, tokens }); + em = ({ type, raw, text, tokens }: Tokens.Em): string => super.em({ type, raw, text, tokens }); + codespan = ({ type, raw, text }: Tokens.Codespan): string => super.codespan({ type, raw, text }); + br = ({ type, raw }: Tokens.Br): string => super.br({ type, raw }); + del = ({ type, raw, text, tokens }: Tokens.Del): string => super.del({ type, raw, text, tokens }); + link = ({ type, raw, href, title, text, tokens }: Tokens.Link): string => super.link({ type, raw, href, title, text, tokens }); + image = ({ type, raw, href, title, text }: Tokens.Image): string => super.image({ type, raw, href, title, text }); } const rendererOptions: MarkedOptions = renderer.options; const textRenderer = new marked.TextRenderer(); -console.log(textRenderer.strong(text)); +console.log(textRenderer.strong({ type : 'strong', raw, text, tokens })); const parseTestText = '- list1\n - list1.1\n\n listend'; const parseTestTokens: TokensList = marked.lexer(parseTestText, options); @@ -135,14 +136,14 @@ marked.use({ renderer }, { tokenizer }); marked.use({ renderer: { - heading(text, level) { - if (level > 3) { + heading({ text, depth }) { + if (depth > 3) { return `

    ${text}

    `; } return false; }, - listitem(text, task, checked) { + listitem({ text, task, checked }) { if (task) return `
  • ${text}
  • \n`; else return `
  • ${text}
  • \n`; } diff --git a/test/unit/Lexer.test.js b/test/unit/Lexer.test.js index 8a331fbbe7..fbf932090a 100644 --- a/test/unit/Lexer.test.js +++ b/test/unit/Lexer.test.js @@ -196,22 +196,30 @@ lheading 2 header: [ { text: 'a', - tokens: [{ type: 'text', raw: 'a', text: 'a' }] + tokens: [{ type: 'text', raw: 'a', text: 'a' }], + header: true, + align: null }, { text: 'b', - tokens: [{ type: 'text', raw: 'b', text: 'b' }] + tokens: [{ type: 'text', raw: 'b', text: 'b' }], + header: true, + align: null } ], rows: [ [ { text: '1', - tokens: [{ type: 'text', raw: '1', text: '1' }] + tokens: [{ type: 'text', raw: '1', text: '1' }], + header: false, + align: null }, { text: '2', - tokens: [{ type: 'text', raw: '2', text: '2' }] + tokens: [{ type: 'text', raw: '2', text: '2' }], + header: false, + align: null } ] ] @@ -243,22 +251,30 @@ paragraph 1 header: [ { text: 'a', - tokens: [{ type: 'text', raw: 'a', text: 'a' }] + tokens: [{ type: 'text', raw: 'a', text: 'a' }], + header: true, + align: null }, { text: 'b', - tokens: [{ type: 'text', raw: 'b', text: 'b' }] + tokens: [{ type: 'text', raw: 'b', text: 'b' }], + header: true, + align: null } ], rows: [ [ { text: '1', - tokens: [{ type: 'text', raw: '1', text: '1' }] + tokens: [{ type: 'text', raw: '1', text: '1' }], + header: false, + align: null }, { text: '2', - tokens: [{ type: 'text', raw: '2', text: '2' }] + tokens: [{ type: 'text', raw: '2', text: '2' }], + header: false, + align: null } ] ] @@ -284,30 +300,42 @@ paragraph 1 header: [ { text: 'a', - tokens: [{ type: 'text', raw: 'a', text: 'a' }] + tokens: [{ type: 'text', raw: 'a', text: 'a' }], + header: true, + align: 'left' }, { text: 'b', - tokens: [{ type: 'text', raw: 'b', text: 'b' }] + tokens: [{ type: 'text', raw: 'b', text: 'b' }], + header: true, + align: 'center' }, { text: 'c', - tokens: [{ type: 'text', raw: 'c', text: 'c' }] + tokens: [{ type: 'text', raw: 'c', text: 'c' }], + header: true, + align: 'right' } ], rows: [ [ { text: '1', - tokens: [{ type: 'text', raw: '1', text: '1' }] + tokens: [{ type: 'text', raw: '1', text: '1' }], + header: false, + align: 'left' }, { text: '2', - tokens: [{ type: 'text', raw: '2', text: '2' }] + tokens: [{ type: 'text', raw: '2', text: '2' }], + header: false, + align: 'center' }, { text: '3', - tokens: [{ type: 'text', raw: '3', text: '3' }] + tokens: [{ type: 'text', raw: '3', text: '3' }], + header: false, + align: 'right' } ] ] @@ -333,22 +361,30 @@ a | b header: [ { text: 'a', - tokens: [{ type: 'text', raw: 'a', text: 'a' }] + tokens: [{ type: 'text', raw: 'a', text: 'a' }], + header: true, + align: null }, { text: 'b', - tokens: [{ type: 'text', raw: 'b', text: 'b' }] + tokens: [{ type: 'text', raw: 'b', text: 'b' }], + header: true, + align: null } ], rows: [ [ { text: '1', - tokens: [{ type: 'text', raw: '1', text: '1' }] + tokens: [{ type: 'text', raw: '1', text: '1' }], + header: false, + align: null }, { text: '2', - tokens: [{ type: 'text', raw: '2', text: '2' }] + tokens: [{ type: 'text', raw: '2', text: '2' }], + header: false, + align: null } ] ] diff --git a/test/unit/Parser.test.js b/test/unit/Parser.test.js index 5e2a6f3f53..c8b151c2ea 100644 --- a/test/unit/Parser.test.js +++ b/test/unit/Parser.test.js @@ -77,22 +77,30 @@ describe('Parser', () => { header: [ { text: 'a', - tokens: [{ type: 'text', raw: 'a', text: 'a' }] + tokens: [{ type: 'text', raw: 'a', text: 'a' }], + header: true, + align: 'left' }, { text: 'b', - tokens: [{ type: 'text', raw: 'b', text: 'b' }] + tokens: [{ type: 'text', raw: 'b', text: 'b' }], + header: true, + align: 'right' } ], rows: [ [ { text: '1', - tokens: [{ type: 'text', raw: '1', text: '1' }] + tokens: [{ type: 'text', raw: '1', text: '1' }], + header: false, + align: 'left' }, { text: '2', - tokens: [{ type: 'text', raw: '2', text: '2' }] + tokens: [{ type: 'text', raw: '2', text: '2' }], + header: false, + align: 'right' } ] ] @@ -273,6 +281,7 @@ describe('Parser', () => { { task: false, checked: undefined, + loose: true, tokens: [ { type: 'text', @@ -284,6 +293,7 @@ describe('Parser', () => { { task: false, checked: undefined, + loose: true, tokens: [ { type: 'text', diff --git a/test/unit/marked.test.js b/test/unit/marked.test.js index fee341557b..0277039843 100644 --- a/test/unit/marked.test.js +++ b/test/unit/marked.test.js @@ -38,7 +38,7 @@ describe('marked unit', () => { const md = 'HTML Image: MY IMAGE'; marked.parse(md, { renderer }); - assert.strictEqual(renderer.html.mock.calls[0].arguments[0], 'MY IMAGE'); + assert.strictEqual(renderer.html.mock.calls[0].arguments[0].raw, 'MY IMAGE'); }); }); @@ -489,8 +489,9 @@ describe('marked unit', () => { return false; } }, + useNewRenderer: true, renderer: { - heading(text, depth, raw) { + heading({ text, depth }) { if (text === name) { return `${text}\n`; } @@ -691,8 +692,9 @@ used extension2 walked

    it('should use renderer', () => { const extension = { + useNewRenderer: true, renderer: { - paragraph(text) { + paragraph() { return 'extension'; } } @@ -700,7 +702,7 @@ used extension2 walked

    mock.method(extension.renderer, 'paragraph'); marked.use(extension); const html = marked.parse('text'); - assert.strictEqual(extension.renderer.paragraph.mock.calls[0].arguments[0], 'text'); + assert.strictEqual(extension.renderer.paragraph.mock.calls[0].arguments[0].raw, 'text'); assert.strictEqual(html, 'extension'); }); @@ -772,18 +774,20 @@ used extension2 walked

    it('should use last extension function and not override others', () => { const extension1 = { + useNewRenderer: true, renderer: { - paragraph(text) { + paragraph() { return 'extension1 paragraph\n'; }, - html(html) { + html() { return 'extension1 html\n'; } } }; const extension2 = { + useNewRenderer: true, renderer: { - paragraph(text) { + paragraph() { return 'extension2 paragraph\n'; } } @@ -802,8 +806,9 @@ paragraph it('should use previous extension when returning false', () => { const extension1 = { + useNewRenderer: true, renderer: { - paragraph(text) { + paragraph({ text }) { if (text !== 'original') { return 'extension1 paragraph\n'; } @@ -812,8 +817,9 @@ paragraph } }; const extension2 = { + useNewRenderer: true, renderer: { - paragraph(text) { + paragraph({ text }) { if (text !== 'extension1' && text !== 'original') { return 'extension2 paragraph\n'; } @@ -835,6 +841,7 @@ original it('should get options with this.options', () => { const extension = { + useNewRenderer: true, renderer: { heading: () => { return this && this.options ? 'arrow options\n' : 'arrow no options\n';