From b1fdccee60927ddfc8edc27442999837ec0909a7 Mon Sep 17 00:00:00 2001 From: Vitaly Puzrin Date: Tue, 5 Dec 2023 13:07:47 +0200 Subject: [PATCH] Rewrite to ESM --- .eslintrc.yml | 162 +++------------------- .github/dependabot.yml | 13 ++ .github/workflows/ci.yml | 34 +++++ .gitignore | 2 +- .travis.yml | 5 - CHANGELOG.md | 7 + bower.json | 27 ---- dist/markdown-it-deflist.js | 239 -------------------------------- dist/markdown-it-deflist.min.js | 7 - index.js | 228 ------------------------------ index.mjs | 203 +++++++++++++++++++++++++++ package.json | 46 +++--- rollup.config.mjs | 74 ++++++++++ support/header.js | 6 - test/cjs.js | 11 ++ test/test.js | 14 -- test/test.mjs | 13 ++ 17 files changed, 403 insertions(+), 688 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml delete mode 100644 bower.json delete mode 100644 dist/markdown-it-deflist.js delete mode 100644 dist/markdown-it-deflist.min.js delete mode 100644 index.js create mode 100644 index.mjs create mode 100644 rollup.config.mjs delete mode 100644 support/header.js create mode 100644 test/cjs.js delete mode 100644 test/test.js create mode 100644 test/test.mjs diff --git a/.eslintrc.yml b/.eslintrc.yml index ec488c2..1cd8ca5 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,146 +1,22 @@ -env: - node: true - browser: false - es6: false +extends: standard -ignorePatterns: - - coverage - - dist - -rules: - accessor-pairs: 2 - array-bracket-spacing: [ 2, "always", { "singleValue": true, "objectsInArrays": true, "arraysInArrays": true } ] - block-scoped-var: 2 - block-spacing: 2 - brace-style: [ 2, '1tbs', { allowSingleLine: true } ] - # Postponed - #callback-return: 2 - comma-dangle: 2 - comma-spacing: 2 - comma-style: 2 - computed-property-spacing: [ 2, never ] - consistent-this: [ 2, self ] - consistent-return: 2 - # ? change to multi - curly: [ 2, 'multi-line' ] - dot-notation: 2 - eol-last: 2 - eqeqeq: 2 - func-style: [ 2, declaration ] - # Postponed - #global-require: 2 - guard-for-in: 2 - handle-callback-err: 2 +overrides: + - + files: [ '*.mjs' ] + rules: + no-restricted-globals: [ 2, require, __dirname ] + - + files: [ 'test/**' ] + env: { mocha: true } + - + files: [ 'lib/**', 'index.mjs' ] + parserOptions: { ecmaVersion: 2015 } - indent: [ 2, 2, { VariableDeclarator: { var: 2, let: 2, const: 3 }, SwitchCase: 1, ignoreComments: true } ] +ignorePatterns: + - demo/ + - dist/ + - benchmark/extra/ - # key-spacing: [ 2, { "align": "value" } ] - keyword-spacing: 2 - linebreak-style: 2 - max-depth: [ 1, 6 ] - max-nested-callbacks: [ 1, 4 ] - # string can exceed 80 chars, but should not overflow github website :) - max-len: [ 2, 120, 1000 ] - new-cap: 2 - new-parens: 2 - # Postponed - #newline-after-var: 2 - no-alert: 2 - no-array-constructor: 2 - no-bitwise: 2 - no-caller: 2 - #no-case-declarations: 2 - no-catch-shadow: 2 - no-cond-assign: 2 - no-console: 1 - no-constant-condition: 2 - #no-control-regex: 2 - no-debugger: 2 - no-delete-var: 2 - no-div-regex: 2 - no-dupe-args: 2 - no-dupe-keys: 2 - no-duplicate-case: 2 - no-else-return: 2 - # Tend to drop - # no-empty: 1 - no-empty-character-class: 2 - no-empty-pattern: 2 - no-eq-null: 2 - no-eval: 2 - no-ex-assign: 2 - no-extend-native: 2 - no-extra-bind: 2 - no-extra-boolean-cast: 2 - no-extra-semi: 2 - no-fallthrough: 2 - no-floating-decimal: 2 - no-func-assign: 2 - # Postponed - #no-implicit-coercion: [2, { "boolean": true, "number": true, "string": true } ] - no-implied-eval: 2 - no-inner-declarations: 2 - no-invalid-regexp: 2 - no-irregular-whitespace: 2 - no-iterator: 2 - no-label-var: 2 - no-labels: 2 - no-lone-blocks: 2 - no-lonely-if: 2 - no-loop-func: 2 - no-mixed-requires: 2 - no-mixed-spaces-and-tabs: 2 - # Postponed - #no-native-reassign: 2 - no-negated-in-lhs: 2 - # Postponed - #no-nested-ternary: 2 - no-new: 2 - no-new-func: 2 - no-new-object: 2 - no-new-require: 2 - no-new-wrappers: 2 - no-obj-calls: 2 - no-octal: 2 - no-octal-escape: 2 - no-path-concat: 2 - no-proto: 2 - no-redeclare: 2 - # Postponed - #no-regex-spaces: 2 - no-return-assign: 2 - no-self-compare: 2 - no-sequences: 2 - no-shadow: 2 - no-shadow-restricted-names: 2 - no-sparse-arrays: 2 - no-trailing-spaces: 2 - no-undef: 2 - no-undef-init: 2 - no-undefined: 2 - no-unexpected-multiline: 2 - no-unreachable: 2 - no-unused-expressions: 2 - no-unused-vars: 2 - no-use-before-define: 2 - no-void: 2 - no-with: 2 - object-curly-spacing: [ 2, always, { "objectsInObjects": true, "arraysInObjects": true } ] - operator-assignment: 1 - # Postponed - #operator-linebreak: [ 2, after ] - semi: 2 - semi-spacing: 2 - space-before-function-paren: [ 2, { "anonymous": "always", "named": "never" } ] - space-in-parens: [ 2, never ] - space-infix-ops: 2 - space-unary-ops: 2 - # Postponed - #spaced-comment: [ 1, always, { exceptions: [ '/', '=' ] } ] - strict: [ 2, global ] - quotes: [ 2, single, avoid-escape ] - quote-props: [ 1, 'as-needed', { "keywords": true } ] - radix: 2 - use-isnan: 2 - valid-typeof: 2 - yoda: [ 2, never, { "exceptRange": true } ] +rules: + camelcase: 0 + no-multi-spaces: 0 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b4bceaf --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + + - package-ecosystem: npm + directory: / + schedule: + interval: daily + allow: + - dependency-type: production diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..241583b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + pull_request: + schedule: + - cron: '0 0 * * 3' + +jobs: + test: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [ '18' ] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - run: npm install + + - name: Test + run: npm test + + - name: Upload coverage report to coveralls.io + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index a52b700..a43f30a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.nyc_output node_modules/ coverage/ +dist/ *.log diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cfc5d95..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - node - - lts/* -after_success: npm run report-coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md index 22b03a7..6ace16f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +3.0.0 / 2023-12-03 +------------------ + +- Rewrite to ESM. +- Remove `dist/` from repo (build on package publish). + + 2.1.0 / 2020-09-10 ------------------ diff --git a/bower.json b/bower.json deleted file mode 100644 index 5efc42d..0000000 --- a/bower.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "markdown-it-deflist", - "main": "dist/markdown-it-deflist.js", - "homepage": "https://github.com/markdown-it/markdown-it-deflist", - "description": "
tag for markdown-it markdown parser.", - "keywords": [ - "markdown-it-plugin", - "markdown-it", - "markdown", - "definition list" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "benchmark", - "bower_components", - "coverage", - "demo", - "docs", - "lib", - "node_modules", - "support", - "test", - "Makefile", - "index*" - ] -} diff --git a/dist/markdown-it-deflist.js b/dist/markdown-it-deflist.js deleted file mode 100644 index a3f14d0..0000000 --- a/dist/markdown-it-deflist.js +++ /dev/null @@ -1,239 +0,0 @@ -/*! - -markdown-it-deflist -https://github.com/markdown-it/markdown-it-deflist - -*/ - -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownitDeflist = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= max) { return -1; } - - // Check bullet - marker = state.src.charCodeAt(start++); - if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1; } - - pos = state.skipSpaces(start); - - // require space after ":" - if (start === pos) { return -1; } - - // no empty definitions, e.g. " : " - if (pos >= max) { return -1; } - - return start; - } - - function markTightParagraphs(state, idx) { - var i, l, - level = state.level + 2; - - for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) { - if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { - state.tokens[i + 2].hidden = true; - state.tokens[i].hidden = true; - i += 2; - } - } - } - - function deflist(state, startLine, endLine, silent) { - var ch, - contentStart, - ddLine, - dtLine, - itemLines, - listLines, - listTokIdx, - max, - nextLine, - offset, - oldDDIndent, - oldIndent, - oldParentType, - oldSCount, - oldTShift, - oldTight, - pos, - prevEmptyEnd, - tight, - token; - - if (silent) { - // quirk: validation mode validates a dd block only, not a whole deflist - if (state.ddIndent < 0) { return false; } - return skipMarker(state, startLine) >= 0; - } - - nextLine = startLine + 1; - if (nextLine >= endLine) { return false; } - - if (state.isEmpty(nextLine)) { - nextLine++; - if (nextLine >= endLine) { return false; } - } - - if (state.sCount[nextLine] < state.blkIndent) { return false; } - contentStart = skipMarker(state, nextLine); - if (contentStart < 0) { return false; } - - // Start list - listTokIdx = state.tokens.length; - tight = true; - - token = state.push('dl_open', 'dl', 1); - token.map = listLines = [ startLine, 0 ]; - - // - // Iterate list items - // - - dtLine = startLine; - ddLine = nextLine; - - // One definition list can contain multiple DTs, - // and one DT can be followed by multiple DDs. - // - // Thus, there is two loops here, and label is - // needed to break out of the second one - // - /*eslint no-labels:0,block-scoped-var:0*/ - OUTER: - for (;;) { - prevEmptyEnd = false; - - token = state.push('dt_open', 'dt', 1); - token.map = [ dtLine, dtLine ]; - - token = state.push('inline', '', 0); - token.map = [ dtLine, dtLine ]; - token.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim(); - token.children = []; - - token = state.push('dt_close', 'dt', -1); - - for (;;) { - token = state.push('dd_open', 'dd', 1); - token.map = itemLines = [ nextLine, 0 ]; - - pos = contentStart; - max = state.eMarks[ddLine]; - offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine]); - - while (pos < max) { - ch = state.src.charCodeAt(pos); - - if (isSpace(ch)) { - if (ch === 0x09) { - offset += 4 - offset % 4; - } else { - offset++; - } - } else { - break; - } - - pos++; - } - - contentStart = pos; - - oldTight = state.tight; - oldDDIndent = state.ddIndent; - oldIndent = state.blkIndent; - oldTShift = state.tShift[ddLine]; - oldSCount = state.sCount[ddLine]; - oldParentType = state.parentType; - state.blkIndent = state.ddIndent = state.sCount[ddLine] + 2; - state.tShift[ddLine] = contentStart - state.bMarks[ddLine]; - state.sCount[ddLine] = offset; - state.tight = true; - state.parentType = 'deflist'; - - state.md.block.tokenize(state, ddLine, endLine, true); - - // If any of list item is tight, mark list as tight - if (!state.tight || prevEmptyEnd) { - tight = false; - } - // Item become loose if finish with empty line, - // but we should filter last element, because it means list finish - prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1); - - state.tShift[ddLine] = oldTShift; - state.sCount[ddLine] = oldSCount; - state.tight = oldTight; - state.parentType = oldParentType; - state.blkIndent = oldIndent; - state.ddIndent = oldDDIndent; - - token = state.push('dd_close', 'dd', -1); - - itemLines[1] = nextLine = state.line; - - if (nextLine >= endLine) { break OUTER; } - - if (state.sCount[nextLine] < state.blkIndent) { break OUTER; } - contentStart = skipMarker(state, nextLine); - if (contentStart < 0) { break; } - - ddLine = nextLine; - - // go to the next loop iteration: - // insert DD tag and repeat checking - } - - if (nextLine >= endLine) { break; } - dtLine = nextLine; - - if (state.isEmpty(dtLine)) { break; } - if (state.sCount[dtLine] < state.blkIndent) { break; } - - ddLine = dtLine + 1; - if (ddLine >= endLine) { break; } - if (state.isEmpty(ddLine)) { ddLine++; } - if (ddLine >= endLine) { break; } - - if (state.sCount[ddLine] < state.blkIndent) { break; } - contentStart = skipMarker(state, ddLine); - if (contentStart < 0) { break; } - - // go to the next loop iteration: - // insert DT and DD tags and repeat checking - } - - // Finilize list - token = state.push('dl_close', 'dl', -1); - - listLines[1] = nextLine; - - state.line = nextLine; - - // mark paragraphs tight if needed - if (tight) { - markTightParagraphs(state, listTokIdx); - } - - return true; - } - - - md.block.ruler.before('paragraph', 'deflist', deflist, { alt: [ 'paragraph', 'reference', 'blockquote' ] }); -}; - -},{}]},{},[])("/") -}); diff --git a/dist/markdown-it-deflist.min.js b/dist/markdown-it-deflist.min.js deleted file mode 100644 index 30ed4e2..0000000 --- a/dist/markdown-it-deflist.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - -markdown-it-deflist -https://github.com/markdown-it/markdown-it-deflist - -*/ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).markdownitDeflist=e()}}((function(){return function e(t,n,r){function i(f,d){if(!n[f]){if(!t[f]){var s="function"==typeof require&&require;if(!d&&s)return s(f,!0);if(o)return o(f,!0);var u=new Error("Cannot find module '"+f+"'");throw u.code="MODULE_NOT_FOUND",u}var a=n[f]={exports:{}};t[f][0].call(a.exports,(function(e){return i(t[f][1][e]||e)}),a,a.exports,e,t,n,r)}return n[f].exports}for(var o="function"==typeof require&&require,f=0;f=o||126!==(r=e.src.charCodeAt(i++))&&58!==r||i===(n=e.skipSpaces(i))||n>=o?-1:i}e.block.ruler.before("paragraph","deflist",(function(e,r,i,o){var f,d,s,u,a,l,p,k,c,h,b,y,m,g,C,I,v,_,w,x;if(o)return!(e.ddIndent<0)&&n(e,r)>=0;if((c=r+1)>=i)return!1;if(e.isEmpty(c)&&++c>=i)return!1;if(e.sCount[c]1&&e.isEmpty(e.line-1),e.tShift[s]=C,e.sCount[s]=g,e.tight=I,e.parentType=m,e.blkIndent=y,e.ddIndent=b,x=e.push("dd_close","dd",-1),a[1]=c=e.line,c>=i)break e;if(e.sCount[c]=i)break;if(u=c,e.isEmpty(u))break;if(e.sCount[u]=i)break;if(e.isEmpty(s)&&s++,s>=i)break;if(e.sCount[s]= max) { return -1; } - - // Check bullet - marker = state.src.charCodeAt(start++); - if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1; } - - pos = state.skipSpaces(start); - - // require space after ":" - if (start === pos) { return -1; } - - // no empty definitions, e.g. " : " - if (pos >= max) { return -1; } - - return start; - } - - function markTightParagraphs(state, idx) { - var i, l, - level = state.level + 2; - - for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) { - if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { - state.tokens[i + 2].hidden = true; - state.tokens[i].hidden = true; - i += 2; - } - } - } - - function deflist(state, startLine, endLine, silent) { - var ch, - contentStart, - ddLine, - dtLine, - itemLines, - listLines, - listTokIdx, - max, - nextLine, - offset, - oldDDIndent, - oldIndent, - oldParentType, - oldSCount, - oldTShift, - oldTight, - pos, - prevEmptyEnd, - tight, - token; - - if (silent) { - // quirk: validation mode validates a dd block only, not a whole deflist - if (state.ddIndent < 0) { return false; } - return skipMarker(state, startLine) >= 0; - } - - nextLine = startLine + 1; - if (nextLine >= endLine) { return false; } - - if (state.isEmpty(nextLine)) { - nextLine++; - if (nextLine >= endLine) { return false; } - } - - if (state.sCount[nextLine] < state.blkIndent) { return false; } - contentStart = skipMarker(state, nextLine); - if (contentStart < 0) { return false; } - - // Start list - listTokIdx = state.tokens.length; - tight = true; - - token = state.push('dl_open', 'dl', 1); - token.map = listLines = [ startLine, 0 ]; - - // - // Iterate list items - // - - dtLine = startLine; - ddLine = nextLine; - - // One definition list can contain multiple DTs, - // and one DT can be followed by multiple DDs. - // - // Thus, there is two loops here, and label is - // needed to break out of the second one - // - /*eslint no-labels:0,block-scoped-var:0*/ - OUTER: - for (;;) { - prevEmptyEnd = false; - - token = state.push('dt_open', 'dt', 1); - token.map = [ dtLine, dtLine ]; - - token = state.push('inline', '', 0); - token.map = [ dtLine, dtLine ]; - token.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim(); - token.children = []; - - token = state.push('dt_close', 'dt', -1); - - for (;;) { - token = state.push('dd_open', 'dd', 1); - token.map = itemLines = [ nextLine, 0 ]; - - pos = contentStart; - max = state.eMarks[ddLine]; - offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine]); - - while (pos < max) { - ch = state.src.charCodeAt(pos); - - if (isSpace(ch)) { - if (ch === 0x09) { - offset += 4 - offset % 4; - } else { - offset++; - } - } else { - break; - } - - pos++; - } - - contentStart = pos; - - oldTight = state.tight; - oldDDIndent = state.ddIndent; - oldIndent = state.blkIndent; - oldTShift = state.tShift[ddLine]; - oldSCount = state.sCount[ddLine]; - oldParentType = state.parentType; - state.blkIndent = state.ddIndent = state.sCount[ddLine] + 2; - state.tShift[ddLine] = contentStart - state.bMarks[ddLine]; - state.sCount[ddLine] = offset; - state.tight = true; - state.parentType = 'deflist'; - - state.md.block.tokenize(state, ddLine, endLine, true); - - // If any of list item is tight, mark list as tight - if (!state.tight || prevEmptyEnd) { - tight = false; - } - // Item become loose if finish with empty line, - // but we should filter last element, because it means list finish - prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1); - - state.tShift[ddLine] = oldTShift; - state.sCount[ddLine] = oldSCount; - state.tight = oldTight; - state.parentType = oldParentType; - state.blkIndent = oldIndent; - state.ddIndent = oldDDIndent; - - token = state.push('dd_close', 'dd', -1); - - itemLines[1] = nextLine = state.line; - - if (nextLine >= endLine) { break OUTER; } - - if (state.sCount[nextLine] < state.blkIndent) { break OUTER; } - contentStart = skipMarker(state, nextLine); - if (contentStart < 0) { break; } - - ddLine = nextLine; - - // go to the next loop iteration: - // insert DD tag and repeat checking - } - - if (nextLine >= endLine) { break; } - dtLine = nextLine; - - if (state.isEmpty(dtLine)) { break; } - if (state.sCount[dtLine] < state.blkIndent) { break; } - - ddLine = dtLine + 1; - if (ddLine >= endLine) { break; } - if (state.isEmpty(ddLine)) { ddLine++; } - if (ddLine >= endLine) { break; } - - if (state.sCount[ddLine] < state.blkIndent) { break; } - contentStart = skipMarker(state, ddLine); - if (contentStart < 0) { break; } - - // go to the next loop iteration: - // insert DT and DD tags and repeat checking - } - - // Finilize list - token = state.push('dl_close', 'dl', -1); - - listLines[1] = nextLine; - - state.line = nextLine; - - // mark paragraphs tight if needed - if (tight) { - markTightParagraphs(state, listTokIdx); - } - - return true; - } - - - md.block.ruler.before('paragraph', 'deflist', deflist, { alt: [ 'paragraph', 'reference', 'blockquote' ] }); -}; diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..9a03ea0 --- /dev/null +++ b/index.mjs @@ -0,0 +1,203 @@ +// Process definition lists +// +export default function deflist_plugin (md) { + const isSpace = md.utils.isSpace + + // Search `[:~][\n ]`, returns next pos after marker on success + // or -1 on fail. + function skipMarker (state, line) { + let start = state.bMarks[line] + state.tShift[line] + const max = state.eMarks[line] + + if (start >= max) { return -1 } + + // Check bullet + const marker = state.src.charCodeAt(start++) + if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1 } + + const pos = state.skipSpaces(start) + + // require space after ":" + if (start === pos) { return -1 } + + // no empty definitions, e.g. " : " + if (pos >= max) { return -1 } + + return start + } + + function markTightParagraphs (state, idx) { + const level = state.level + 2 + + for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) { + if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { + state.tokens[i + 2].hidden = true + state.tokens[i].hidden = true + i += 2 + } + } + } + + function deflist (state, startLine, endLine, silent) { + if (silent) { + // quirk: validation mode validates a dd block only, not a whole deflist + if (state.ddIndent < 0) { return false } + return skipMarker(state, startLine) >= 0 + } + + let nextLine = startLine + 1 + if (nextLine >= endLine) { return false } + + if (state.isEmpty(nextLine)) { + nextLine++ + if (nextLine >= endLine) { return false } + } + + if (state.sCount[nextLine] < state.blkIndent) { return false } + let contentStart = skipMarker(state, nextLine) + if (contentStart < 0) { return false } + + // Start list + const listTokIdx = state.tokens.length + let tight = true + + const token_dl_o = state.push('dl_open', 'dl', 1) + const listLines = [startLine, 0] + token_dl_o.map = listLines + + // + // Iterate list items + // + + let dtLine = startLine + let ddLine = nextLine + + // One definition list can contain multiple DTs, + // and one DT can be followed by multiple DDs. + // + // Thus, there is two loops here, and label is + // needed to break out of the second one + // + /* eslint no-labels:0,block-scoped-var:0 */ + OUTER: + for (;;) { + let prevEmptyEnd = false + + const token_dt_o = state.push('dt_open', 'dt', 1) + token_dt_o.map = [dtLine, dtLine] + + const token_i = state.push('inline', '', 0) + token_i.map = [dtLine, dtLine] + token_i.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim() + token_i.children = [] + + state.push('dt_close', 'dt', -1) + + for (;;) { + const token_dd_o = state.push('dd_open', 'dd', 1) + const itemLines = [nextLine, 0] + token_dd_o.map = itemLines + + let pos = contentStart + const max = state.eMarks[ddLine] + let offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine]) + + while (pos < max) { + const ch = state.src.charCodeAt(pos) + + if (isSpace(ch)) { + if (ch === 0x09) { + offset += 4 - offset % 4 + } else { + offset++ + } + } else { + break + } + + pos++ + } + + contentStart = pos + + const oldTight = state.tight + const oldDDIndent = state.ddIndent + const oldIndent = state.blkIndent + const oldTShift = state.tShift[ddLine] + const oldSCount = state.sCount[ddLine] + const oldParentType = state.parentType + state.blkIndent = state.ddIndent = state.sCount[ddLine] + 2 + state.tShift[ddLine] = contentStart - state.bMarks[ddLine] + state.sCount[ddLine] = offset + state.tight = true + state.parentType = 'deflist' + + state.md.block.tokenize(state, ddLine, endLine, true) + + // If any of list item is tight, mark list as tight + if (!state.tight || prevEmptyEnd) { + tight = false + } + // Item become loose if finish with empty line, + // but we should filter last element, because it means list finish + prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1) + + state.tShift[ddLine] = oldTShift + state.sCount[ddLine] = oldSCount + state.tight = oldTight + state.parentType = oldParentType + state.blkIndent = oldIndent + state.ddIndent = oldDDIndent + + state.push('dd_close', 'dd', -1) + + itemLines[1] = nextLine = state.line + + if (nextLine >= endLine) { break OUTER } + + if (state.sCount[nextLine] < state.blkIndent) { break OUTER } + contentStart = skipMarker(state, nextLine) + if (contentStart < 0) { break } + + ddLine = nextLine + + // go to the next loop iteration: + // insert DD tag and repeat checking + } + + if (nextLine >= endLine) { break } + dtLine = nextLine + + if (state.isEmpty(dtLine)) { break } + if (state.sCount[dtLine] < state.blkIndent) { break } + + ddLine = dtLine + 1 + if (ddLine >= endLine) { break } + if (state.isEmpty(ddLine)) { ddLine++ } + if (ddLine >= endLine) { break } + + if (state.sCount[ddLine] < state.blkIndent) { break } + contentStart = skipMarker(state, ddLine) + if (contentStart < 0) { break } + + // go to the next loop iteration: + // insert DT and DD tags and repeat checking + } + + // Finilize list + state.push('dl_close', 'dl', -1) + + listLines[1] = nextLine + + state.line = nextLine + + // mark paragraphs tight if needed + if (tight) { + markTightParagraphs(state, listTokIdx) + } + + return true + } + + md.block.ruler.before('paragraph', 'deflist', deflist, { alt: ['paragraph', 'reference', 'blockquote'] }) +}; diff --git a/package.json b/package.json index 35a65d2..429d930 100644 --- a/package.json +++ b/package.json @@ -10,29 +10,39 @@ ], "repository": "markdown-it/markdown-it-deflist.git", "license": "MIT", - "scripts": { - "lint": "eslint .", - "test": "npm run lint && nyc mocha", - "coverage": "npm run test && nyc report --reporter=html", - "report-coveralls": "nyc report --reporter=text-lcov | coveralls", - "browserify": "browserify -r ./ -s markdownitDeflist -p [ browserify-header --file support/header.js ] > dist/markdown-it-deflist.js", - "minify": "terser dist/markdown-it-deflist.js -b beautify=false,ascii_only=true -c -m > dist/markdown-it-deflist.min.js", - "build": "npm run browserify && npm run minify" + "main": "dist/index.cjs.js", + "module": "index.mjs", + "exports": { + ".": { + "require": "./dist/index.cjs.js", + "import": "./index.mjs" + }, + "./*": { + "require": "./*", + "import": "./*" + } }, "files": [ - "index.js", + "index.mjs", "lib/", "dist/" ], + "scripts": { + "lint": "eslint .", + "build": "rollup -c", + "test": "npm run lint && npm run build && c8 --exclude dist --exclude test -r text -r html -r lcov mocha", + "prepublishOnly": "npm run lint && npm run build" + }, "devDependencies": { - "browserify": "^16.5.2", - "browserify-header": "^1.0.1", - "coveralls": "^3.1.0", - "eslint": "^7.8.1", - "markdown-it": "markdown-it/markdown-it", - "markdown-it-testgen": "~0.1.0", - "mocha": "^8.1.3", - "nyc": "^15.1.0", - "terser": "^5.3.1" + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "c8": "^8.0.1", + "eslint": "^8.55.0", + "eslint-config-standard": "^17.1.0", + "markdown-it": "^13.0.2", + "markdown-it-testgen": "^0.1.6", + "mocha": "^10.2.0", + "rollup": "^4.6.1" } } diff --git a/rollup.config.mjs b/rollup.config.mjs new file mode 100644 index 0000000..000ffdf --- /dev/null +++ b/rollup.config.mjs @@ -0,0 +1,74 @@ +import resolve from '@rollup/plugin-node-resolve' +import terser from '@rollup/plugin-terser' +import { babel } from '@rollup/plugin-babel' +import { readFileSync } from 'fs' + +const pkg = JSON.parse(readFileSync(new URL('package.json', import.meta.url))) + +function globalName (name) { + const parts = name.split('-') + for (let i = 2; i < parts.length; i++) { + parts[i] = parts[i][0].toUpperCase() + parts[i].slice(1) + } + return parts.join('') +} + +const config_umd_full = { + input: 'index.mjs', + output: [ + { + file: `dist/${pkg.name}.js`, + format: 'umd', + name: globalName(pkg.name), + plugins: [ + // Here terser is used only to force ascii output + terser({ + mangle: false, + compress: false, + format: { comments: 'all', beautify: true, ascii_only: true, indent_level: 2 } + }) + ] + }, + { + file: `dist/${pkg.name}.min.js`, + format: 'umd', + name: globalName(pkg.name), + plugins: [ + terser({ + format: { ascii_only: true } + }) + ] + } + ], + plugins: [ + resolve(), + babel({ babelHelpers: 'bundled' }), + { + banner () { + return `/*! ${pkg.name} ${pkg.version} https://github.com/${pkg.repository} @license ${pkg.license} */` + } + } + ] +} + +const config_cjs_no_deps = { + input: 'index.mjs', + output: { + file: 'dist/index.cjs.js', + format: 'cjs' + }, + external: Object.keys(pkg.dependencies || {}), + plugins: [ + resolve(), + babel({ babelHelpers: 'bundled' }) + ] +} + +let config = [ + config_umd_full, + config_cjs_no_deps +] + +if (process.env.CJS_ONLY) config = [config_cjs_no_deps] + +export default config diff --git a/support/header.js b/support/header.js deleted file mode 100644 index 3babce2..0000000 --- a/support/header.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - -markdown-it-deflist -https://github.com/markdown-it/markdown-it-deflist - -*/ diff --git a/test/cjs.js b/test/cjs.js new file mode 100644 index 0000000..333a5e6 --- /dev/null +++ b/test/cjs.js @@ -0,0 +1,11 @@ +'use strict' +/* eslint-env mocha */ + +const assert = require('node:assert') +const fn = require('../') + +describe('CJS', () => { + it('require', () => { + assert.ok(typeof fn === 'function') + }) +}) diff --git a/test/test.js b/test/test.js deleted file mode 100644 index bbc2e10..0000000 --- a/test/test.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - - -var path = require('path'); -var generate = require('markdown-it-testgen'); - -/*eslint-env mocha*/ - -describe('markdown-it-deflist', function () { - var md = require('markdown-it')() - .use(require('../')); - - generate(path.join(__dirname, 'fixtures/deflist.txt'), md); -}); diff --git a/test/test.mjs b/test/test.mjs new file mode 100644 index 0000000..f9e52fe --- /dev/null +++ b/test/test.mjs @@ -0,0 +1,13 @@ +import { fileURLToPath } from 'node:url' +import markdownit from 'markdown-it' +import generate from 'markdown-it-testgen' + +import deflist from '../index.mjs' + +/* eslint-env mocha */ + +describe('markdown-it-deflist', function () { + const md = markdownit().use(deflist) + + generate(fileURLToPath(new URL('fixtures/deflist.txt', import.meta.url)), md) +})