Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wellformed the table's rowspan and/or colspan attributes #156

Merged
merged 9 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: ci

on: [push, pull_request]

jobs:
test:
name: ${{ matrix.node-version }} on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
node-version: [16.x, 18.x, 20.x, 22.x]
os: [ubuntu-latest, macOS-latest, windows-latest]
runs-on: ${{ matrix.os }}

steps:
- if: runner.os == 'Windows'
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.symlinks true
- uses: actions/checkout@v4
with:
show-progress: false
- name: v${{ matrix.node-version }} on ${{ matrix.os }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
architecture: 'x64'
cache: 'npm'
- run: npm ci
- run: npm test
5 changes: 5 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
/.travis.yml
/.eslintignore
/.eslintrc.js
/.eslintrc.json
/.editorconfig
/.gitignore
/.github
/.devcontainer
/debug.js
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# markdown-it-attrs [![Build Status](https://travis-ci.org/arve0/markdown-it-attrs.svg?branch=master)](https://travis-ci.org/arve0/markdown-it-attrs) [![npm version](https://badge.fury.io/js/markdown-it-attrs.svg)](http://badge.fury.io/js/markdown-it-attrs) [![Coverage Status](https://coveralls.io/repos/github/arve0/markdown-it-attrs/badge.svg?branch=master)](https://coveralls.io/github/arve0/markdown-it-attrs?branch=master) <!-- omit in toc -->
# markdown-it-attrs [![GitHub actions](https://github.com/arve0/markdown-it-attrs/workflows/ci/badge.svg)](https://github.com/arve0/markdown-it-attrs/actions) [![npm version](https://badge.fury.io/js/markdown-it-attrs.svg)](http://badge.fury.io/js/markdown-it-attrs) [![Coverage Status](https://coveralls.io/repos/github/arve0/markdown-it-attrs/badge.svg?branch=master)](https://coveralls.io/github/arve0/markdown-it-attrs?branch=master) <!-- omit in toc -->

Add classes, identifiers and attributes to your markdown with `{.class #identifier attr=value attr2="spaced value"}` curly brackets, similar to [pandoc's header attributes](http://pandoc.org/README.html#extension-header_attributes).

Expand Down Expand Up @@ -250,6 +250,46 @@ Output:
</table>
```

Wellformed the table's _rowspan_ and/or _colspan_ attributes, usage sample below:
```md
| A | B | C | D |
| ----------------------- | --- | --- | ---------------- |
| 1 | 11 | 111 | 1111 {rowspan=3} |
| 2 {colspan=2 rowspan=2} | 22 | 222 | 2222 |
| 3 | 33 | 333 | 3333 |

{border=1}
```

Output:
```html
<table border="1">
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>11</td>
<td>111</td>
<td rowspan="3">1111</td>
</tr>
<tr>
<td colspan="2" rowspan="2">2</td>
<td>22</td>
</tr>
<tr>
<td>3</td>
</tr>
</tbody>
</table>
```

If you need finer control, [decorate](https://github.com/rstacruz/markdown-it-decorate) might help you.

## Custom rendering
Expand Down
75 changes: 70 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,75 @@

const patternsConfig = require('./patterns.js');

/**
* @typedef {import('markdown-it')} MarkdownIt
*
* @typedef {import('markdown-it/lib/rules_core/state_core.mjs').default} StateCore
*
* @typedef {import('markdown-it/lib/token.mjs').default} Token
*
* @typedef {import('markdown-it/lib/token.mjs').Nesting} Nesting
*
* @typedef {Object} Options
* @property {!string} leftDelimiter left delimiter, default is `{`(left curly bracket)
* @property {!string} rightDelimiter right delimiter, default is `}`(right curly bracket)
* @property {AllowedAttribute[]} allowedAttributes empty means no limit
*
* @typedef {string|RegExp} AllowedAttribute rule of allowed attribute
*
* @typedef {[string, string]} AttributePair
*
* @typedef {[number, number]} SourceLineInfo
*
* @typedef {Object} CurlyAttrsPattern
* @property {string} name
* @property {DetectingRule[]} tests
* @property {(tokens: Token[], i: number, j?: number) => void} transform
*
* @typedef {Object} MatchedResult
* @property {boolean} match true means matched
* @property {number?} j postion index number of Array<{@link Token}>
*
* @typedef {(str: string) => boolean} DetectingStrRule
*
* @typedef {Object} DetectingRule rule for testing {@link Token}'s properties
* @property {number=} shift offset index number of Array<{@link Token}>
* @property {number=} position fixed index number of Array<{@link Token}>
* @property {(string | DetectingStrRule)=} type
* @property {(string | DetectingStrRule)=} tag
* @property {DetectingRule[]=} children
* @property {(string | DetectingStrRule)=} content
* @property {(string | DetectingStrRule)=} markup
* @property {(string | DetectingStrRule)=} info
* @property {Nesting=} nesting
* @property {number=} level
* @property {boolean=} block
* @property {boolean=} hidden
* @property {AttributePair[]=} attrs
* @property {SourceLineInfo[]=} map
* @property {any=} meta
*/

/** @type {Options} */
const defaultOptions = {
leftDelimiter: '{',
rightDelimiter: '}',
allowedAttributes: []
};

/**
* @param {MarkdownIt} md
* @param {Options=} options_
*/
module.exports = function attributes(md, options_) {
let options = Object.assign({}, defaultOptions);
options = Object.assign(options, options_);

const patterns = patternsConfig(options);

/**
* @param {StateCore} state
*/
function curlyAttrs(state) {
const tokens = state.tokens;

Expand Down Expand Up @@ -43,12 +100,13 @@ module.exports = function attributes(md, options_) {
/**
* Test if t matches token stream.
*
* @param {array} tokens
* @param {Token[]} tokens
* @param {number} i
* @param {object} t Test to match.
* @return {object} { match: true|false, j: null|number }
* @param {DetectingRule} t
* @returns {MatchedResult}
*/
function test(tokens, i, t) {
/** @type {MatchedResult} */
const res = {
match: false,
j: null // position of child
Expand Down Expand Up @@ -78,7 +136,9 @@ function test(tokens, i, t) {
return res;
}
let match;
/** @type {DetectingRule[]} */
const childTests = t.children;
/** @type {Token[]} */
const children = token.children;
if (childTests.every(tt => tt.position !== undefined)) {
// positions instead of shifts, do not loop all children
Expand Down Expand Up @@ -141,14 +201,19 @@ function isArrayOfFunctions(arr) {
/**
* Get n item of array. Supports negative n, where -1 is last
* element in array.
* @param {array} arr
* @param {Token[]} arr
* @param {number} n
* @returns {Token=}
*/
function get(arr, n) {
return n >= 0 ? arr[n] : arr[arr.length + n];
}

// get last element of array, safe - returns {} if not found
/**
* get last element of array, safe - returns {} if not found
* @param {DetectingRule[]} arr
* @returns {DetectingRule}
*/
function last(arr) {
return arr.slice(-1)[0] || {};
}
Loading