├── .gitignore ├── test ├── fixtures │ ├── text.txt │ └── link.txt ├── cjs.js └── test.mjs ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── CHANGELOG.md ├── .eslintrc.yml ├── index.mjs ├── LICENSE ├── package.json ├── rollup.config.mjs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | dist/ 4 | *.log 5 | -------------------------------------------------------------------------------- /test/fixtures/text.txt: -------------------------------------------------------------------------------- 1 | --- 2 | desc: Text tokens processing 3 | --- 4 | 5 | . 6 | fooo _bar foo_ bar foo beer 7 | . 8 |

baro bar bar bar bar beer

9 | . 10 | -------------------------------------------------------------------------------- /test/cjs.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /* eslint-env mocha */ 3 | 4 | const assert = require('node:assert') 5 | const fn = require('../') 6 | 7 | describe('CJS', () => { 8 | it('require', () => { 9 | assert.ok(typeof fn === 'function') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | 8 | - package-ecosystem: npm 9 | directory: / 10 | schedule: 11 | interval: daily 12 | allow: 13 | - dependency-type: production 14 | -------------------------------------------------------------------------------- /test/fixtures/link.txt: -------------------------------------------------------------------------------- 1 | --- 2 | desc: Link tokens processing 3 | --- 4 | 5 | 6 | . 7 | foo http://google.com bar 8 | . 9 |

foo shmugle.com bar

10 | . 11 | 12 | 13 | . 14 | https://www.mantana.ru 15 | . 16 |

mantana.ru

17 | . 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2.0.1 / 2023-12-05 2 | ------------------ 3 | 4 | - Fixed CJS exports. 5 | 6 | 7 | 2.0.0 / 2023-12-02 8 | ------------------ 9 | 10 | - Rewrite to ESM. 11 | - Remove `dist/` from repo (build on package publish). 12 | 13 | 14 | 0.1.1 / 2015-05-05 15 | ------------------ 16 | 17 | - Fixed rule name set. Thanks to @emgeee. 18 | 19 | 20 | 0.1.0 / 2014-12-29 21 | ------------------ 22 | 23 | - First release. 24 | 25 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: standard 2 | 3 | overrides: 4 | - 5 | files: [ '*.mjs' ] 6 | rules: 7 | no-restricted-globals: [ 2, require, __dirname ] 8 | - 9 | files: [ 'test/**' ] 10 | env: { mocha: true } 11 | - 12 | files: [ 'lib/**', 'index.mjs' ] 13 | parserOptions: { ecmaVersion: 2015 } 14 | 15 | ignorePatterns: 16 | - demo/ 17 | - dist/ 18 | - benchmark/extra/ 19 | 20 | rules: 21 | camelcase: 0 22 | no-multi-spaces: 0 23 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | export default function for_inline_plugin (md, ruleName, tokenType, iterator) { 2 | function scan (state) { 3 | for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { 4 | if (state.tokens[blkIdx].type !== 'inline') continue 5 | 6 | const inlineTokens = state.tokens[blkIdx].children 7 | 8 | for (let i = inlineTokens.length - 1; i >= 0; i--) { 9 | if (inlineTokens[i].type !== tokenType) continue 10 | 11 | iterator(inlineTokens, i) 12 | } 13 | } 14 | } 15 | 16 | md.core.ruler.push(ruleName, scan) 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 0 * * 3' 8 | 9 | jobs: 10 | test: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [ '18' ] 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | 26 | - run: npm install 27 | 28 | - name: Test 29 | run: npm test 30 | 31 | - name: Upload coverage report to coveralls.io 32 | uses: coverallsapp/github-action@master 33 | with: 34 | github-token: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /test/test.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import markdownit from 'markdown-it' 3 | import generate from 'markdown-it-testgen' 4 | 5 | import inlineEach from '../index.mjs' 6 | 7 | describe('markdown-it-for-inline', () => { 8 | let md 9 | 10 | md = markdownit() 11 | .use(inlineEach, 'text_replace', 'text', (tokens, idx) => { 12 | tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar') 13 | }) 14 | 15 | generate(fileURLToPath(new URL('fixtures/text.txt', import.meta.url)), { header: true }, md) 16 | 17 | md = markdownit({ linkify: true }) 18 | .use(inlineEach, 'link_replace', 'link_open', (tokens, idx) => { 19 | if ((tokens[idx + 2].type !== 'link_close') || (tokens[idx + 1].type !== 'text')) { 20 | return 21 | } 22 | tokens[idx + 1].content = tokens[idx + 1].content 23 | .replace(/google/g, 'shmugle') 24 | .replace(/^https?:\/\//, '') 25 | .replace(/^www./, '') 26 | }) 27 | 28 | generate(fileURLToPath(new URL('fixtures/link.txt', import.meta.url)), { header: true }, md) 29 | }) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Vitaly Puzrin. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-it-for-inline", 3 | "version": "2.0.1", 4 | "description": "Inline tokens iterator for markdown-it markdown parser.", 5 | "keywords": [ 6 | "markdown-it-plugin", 7 | "markdown-it", 8 | "markdown", 9 | "iterator" 10 | ], 11 | "repository": "markdown-it/markdown-it-for-inline", 12 | "license": "MIT", 13 | "main": "dist/index.cjs.js", 14 | "module": "index.mjs", 15 | "exports": { 16 | ".": { 17 | "require": "./dist/index.cjs.js", 18 | "import": "./index.mjs" 19 | }, 20 | "./*": { 21 | "require": "./*", 22 | "import": "./*" 23 | } 24 | }, 25 | "files": [ 26 | "index.mjs", 27 | "lib/", 28 | "dist/" 29 | ], 30 | "scripts": { 31 | "lint": "eslint .", 32 | "build": "rollup -c", 33 | "test": "npm run lint && npm run build && c8 --exclude dist --exclude test -r text -r html -r lcov mocha", 34 | "prepublishOnly": "npm run lint && npm run build" 35 | }, 36 | "devDependencies": { 37 | "@rollup/plugin-babel": "^6.0.4", 38 | "@rollup/plugin-node-resolve": "^15.2.3", 39 | "@rollup/plugin-terser": "^0.4.4", 40 | "c8": "^8.0.1", 41 | "eslint": "^8.55.0", 42 | "eslint-config-standard": "^17.1.0", 43 | "markdown-it": "^13.0.2", 44 | "markdown-it-testgen": "^0.1.6", 45 | "mocha": "^10.2.0", 46 | "rollup": "^4.6.1" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve' 2 | import terser from '@rollup/plugin-terser' 3 | import { babel } from '@rollup/plugin-babel' 4 | import { readFileSync } from 'fs' 5 | 6 | const pkg = JSON.parse(readFileSync(new URL('package.json', import.meta.url))) 7 | 8 | function globalName (name) { 9 | const parts = name.split('-') 10 | for (let i = 2; i < parts.length; i++) { 11 | parts[i] = parts[i][0].toUpperCase() + parts[i].slice(1) 12 | } 13 | return parts.join('') 14 | } 15 | 16 | const config_umd_full = { 17 | input: 'index.mjs', 18 | output: [ 19 | { 20 | file: `dist/${pkg.name}.js`, 21 | format: 'umd', 22 | name: globalName(pkg.name), 23 | plugins: [ 24 | // Here terser is used only to force ascii output 25 | terser({ 26 | mangle: false, 27 | compress: false, 28 | format: { comments: 'all', beautify: true, ascii_only: true, indent_level: 2 } 29 | }) 30 | ] 31 | }, 32 | { 33 | file: `dist/${pkg.name}.min.js`, 34 | format: 'umd', 35 | name: globalName(pkg.name), 36 | plugins: [ 37 | terser({ 38 | format: { ascii_only: true } 39 | }) 40 | ] 41 | } 42 | ], 43 | plugins: [ 44 | resolve(), 45 | babel({ babelHelpers: 'bundled' }), 46 | { 47 | banner () { 48 | return `/*! ${pkg.name} ${pkg.version} https://github.com/${pkg.repository} @license ${pkg.license} */` 49 | } 50 | } 51 | ] 52 | } 53 | 54 | const config_cjs_no_deps = { 55 | input: 'index.mjs', 56 | output: { 57 | file: 'dist/index.cjs.js', 58 | format: 'cjs' 59 | }, 60 | external: Object.keys(pkg.dependencies || {}), 61 | plugins: [ 62 | resolve(), 63 | babel({ babelHelpers: 'bundled' }) 64 | ] 65 | } 66 | 67 | let config = [ 68 | config_umd_full, 69 | config_cjs_no_deps 70 | ] 71 | 72 | if (process.env.CJS_ONLY) config = [config_cjs_no_deps] 73 | 74 | export default config 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # markdown-it-for-inline 2 | 3 | [![CI](https://github.com/markdown-it/markdown-it-for-inline/actions/workflows/ci.yml/badge.svg)](https://github.com/markdown-it/markdown-it-for-inline/actions/workflows/ci.yml) 4 | [![NPM version](https://img.shields.io/npm/v/markdown-it-for-inline.svg?style=flat)](https://www.npmjs.org/package/markdown-it-for-inline) 5 | [![Coverage Status](https://img.shields.io/coveralls/markdown-it/markdown-it-for-inline/master.svg?style=flat)](https://coveralls.io/r/markdown-it/markdown-it-for-inline) 6 | 7 | > Inline tokens iterator for [markdown-it](https://github.com/markdown-it/markdown-it) markdown parser. 8 | 9 | This plugin allows to apply function to certain types of inline tokens. Speed 10 | will be not fastest of possible, but you can do quick prototyping of certain 11 | rule types. 12 | 13 | 14 | ## Usage 15 | 16 | ## Install 17 | 18 | node.js, browser: 19 | 20 | ```bash 21 | npm install markdown-it-for-inline --save 22 | bower install markdown-it-for-inline --save 23 | ``` 24 | 25 | ## Use 26 | 27 | ```js 28 | var iterator = require('markdown-it-for-inline'); 29 | 30 | // plugin params are: 31 | // 32 | // - rule name (should be unique) 33 | // - token type to apply 34 | // - function 35 | // 36 | var md = require('markdown-it')() 37 | .use(iterator, 'foo_replace', 'text', function (tokens, idx) { 38 | tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar'); 39 | }); 40 | ``` 41 | 42 | _Differences in browser._ If you load script directly into the page, without 43 | package system, module will add itself globally as `window.markdownitForInline`. 44 | 45 | 46 | __Example 2.__ Cut link prefixes 47 | 48 | ```js 49 | var iterator = require('markdown-it-for-inline'); 50 | 51 | var md = require('markdown-it')({ linkify: true }) 52 | .use(iterator, 'url_beautify', 'link_open', function (tokens, idx) { 53 | // Make sure link contains only text 54 | if ((tokens[idx + 2].type !== 'link_close') || 55 | (tokens[idx + 1].type !== 'text')) { 56 | return; 57 | } 58 | // Do replacement 59 | tokens[idx + 1].content = tokens[idx + 1].content 60 | .replace(/^https?:\/\//, '') 61 | .replace(/^www./, ''); 62 | }); 63 | ``` 64 | 65 | __Example 3.__ Make links open in new window 66 | 67 | ```js 68 | var iterator = require('markdown-it-for-inline'); 69 | 70 | var md = require('markdown-it')({ linkify: true }) 71 | .use(iterator, 'url_new_win', 'link_open', function (tokens, idx) { 72 | tokens[idx].attrPush([ 'target', '_blank' ]); 73 | }); 74 | ``` 75 | 76 | 77 | ## License 78 | 79 | [MIT](https://github.com/markdown-it/markdown-it-for-inline/blob/master/LICENSE) 80 | --------------------------------------------------------------------------------