Skip to content

Rewrite to not mutate given node #1

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

Merged
merged 1 commit into from
Jul 23, 2016
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
1 change: 0 additions & 1 deletion .remarkrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"lint",
"github",
"usage",
"slug",
"validate-links"
],
"settings": {
Expand Down
58 changes: 47 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@ npm install remark-toc
**mdast-util-toc** is also available as an AMD, CommonJS, and globals
module, [uncompressed and compressed][releases].

## Usage

Dependencies:

```javascript
var remark = require('remark');
var toc = require('mdast-util-toc');
```

Transform:
Parse:

```javascript
var input = remark().parse([
var node = remark().parse([
'# Alpha',
'',
'## Bravo',
Expand All @@ -33,11 +35,23 @@ var input = remark().parse([
'## Delta',
''
].join('\n'));
```

TOC:

```javascript
var result = toc(node);
```

toc(input));
Yields:

// { map: [ { type: 'list', ordered: false, children: [{...}] } ],
// index: -1 }
```js
{ index: null,
endIndex: null,
map:
{ type: 'list',
ordered: false,
children: [ { type: 'listItem', loose: true, children: [Object] } ] } }
```

## API
Expand All @@ -46,14 +60,17 @@ toc(input));

Generate a Table of Contents from a Markdown document.

* If specified, looks for the first heading containing the `heading` option
(case insensitive, supports alt/title attributes for links and images too);
* If specified, looks for the first heading containing the `heading`
option (case insensitive, supports alt/title attributes for links
and images too), and returns a table of contents for all following
headings.

* Removes all following contents until an equal or higher heading is found;
* If no `heading` is specified, creates a table of contents for all
headings in `node`.

* Inserts a list representation of the hierarchy of following headings;

* Adds links to following headings, using the same slugs as GitHub.
Links to headings are based on GitHub’s style. Only top-level headings
(those not in blockquotes or lists), are used. The given node is not
modified.

#### `options`

Expand All @@ -68,6 +85,25 @@ Generate a Table of Contents from a Markdown document.
* `tight` (`boolean?`, default: `false`)
— Whether to compile list-items tightly.

#### Returns

An object with the following properties:

* `index` (`number?`)
— Position of the `heading` in `node`. `-1` if no heading
was found, `null` if no heading was given;

* `endIndex` (`number?`)
— Position of the last node after `heading` before the TOC starts.
`-1` if no heading was found, `null` if no heading was given,
same as `index` if there are no nodes between `heading` and the
first heading in the TOC;

* `map` (`Node?`)
— List node representing the generated table of contents.
`null` if no table of contents could be created, either because
no `heading` didn’t exist, or no following headings were found.

## License

[MIT][license] © [Jonathan Haines][author]
Expand Down
9 changes: 6 additions & 3 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
var remark = require('remark');
var toc = require('./index.js');

// Transform:
var input = remark().parse([
// Parse:
var node = remark().parse([
'# Alpha',
'',
'## Bravo',
Expand All @@ -14,5 +14,8 @@ var input = remark().parse([
''
].join('\n'));

// TOC:
var result = toc(node);

// Yields:
console.log('markdown', toc(input));
console.log('js', require('util').inspect(result, {depth: 3}));
26 changes: 10 additions & 16 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,32 @@
*/

/* Expose. */
module.exports = attacher;
module.exports = toc;

/* Dependencies */
var remark = require('remark');
var slug = require('remark-slug');
var toExpression = require('./to-expression');
var search = require('./search');
var contents = require('./contents');

/**
* Attacher.
* Get a TOC representation of `node`.
*
* @param {Mdast} node - MDAST.
* @param {Object} options - Configuration.
* @return {Array} - TOC Markdown.
*/
function attacher(node, options) {
function toc(node, options) {
var settings = options || {};
var heading = settings.heading ? toExpression(settings.heading) : null;
var depth = settings.maxDepth || 6;
var tight = settings.tight;
var result = search(node, heading, settings.maxDepth || 6);
var map = result.map;

var processor = remark().use(slug);
var tree = processor.run(node);
var result = search(tree, heading, depth);
result.map = map.length ? contents(map, settings.tight) : null;

if (result.index === null || !result.map.length) {
return result;
/* No given heading */
if (!heading) {
result.index = result.endIndex = null;
}

return {
map: [contents(result.map, tight)],
index: result.index
};
return result;
}
196 changes: 96 additions & 100 deletions lib/insert.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,103 +6,99 @@
* @fileoverview Generate a Table of Contents (TOC) from a given Markdown file.
*/

/* Expose. */
module.exports = insert;

/* Dependencies */
var listItem = require('./list-item');
var list = require('./list');

/* Constants */
var LIST = 'list';
var LIST_ITEM = 'listItem';
var PARAGRAPH = 'paragraph';
var LINK = 'link';
var TEXT = 'text';

/**
* Insert a `node` into a `parent`.
*
* @param {Object} node - `node` to insert.
* @param {Object} parent - Parent of `node`.
* @param {boolean?} [tight] - Prefer tight list-items.
* @return {undefined}
*/
function insert(node, parent, tight) {
var children = parent.children;
var length = children.length;
var last = children[length - 1];
var isLoose = false;
var index;
var item;

if (node.depth === 1) {
item = listItem();

item.children.push({
type: PARAGRAPH,
children: [
{
type: LINK,
title: null,
url: '#' + node.id,
children: [
{
type: TEXT,
value: node.value
}
]
}
]
});

children.push(item);
} else if (last && last.type === LIST_ITEM) {
insert(node, last, tight);
} else if (last && last.type === LIST) {
node.depth--;

insert(node, last);
} else if (parent.type === LIST) {
item = listItem();

insert(node, item);

children.push(item);
} else {
item = list();
node.depth--;

insert(node, item);

children.push(item);
}

/*
* Properly style list-items with new lines.
*/

if (parent.type === LIST_ITEM) {
parent.loose = tight ? false : children.length > 1;
} else {
if (tight) {
isLoose = false;
} else {
index = -1;

while (++index < length) {
if (children[index].loose) {
isLoose = true;

break;
}
}
}

index = -1;

while (++index < length) {
children[index].loose = isLoose;
}
}
}
/* Expose. */
module.exports = insert;

/* Dependencies */
var listItem = require('./list-item');
var list = require('./list');

/* Constants */
var LIST = 'list';
var LIST_ITEM = 'listItem';
var PARAGRAPH = 'paragraph';
var LINK = 'link';
var TEXT = 'text';

/**
* Insert a `node` into a `parent`.
*
* @param {Object} node - `node` to insert.
* @param {Object} parent - Parent of `node`.
* @param {boolean?} [tight] - Prefer tight list-items.
* @return {undefined}
*/
function insert(node, parent, tight) {
var children = parent.children;
var length = children.length;
var last = children[length - 1];
var isLoose = false;
var index;
var item;

if (node.depth === 1) {
item = listItem();

item.children.push({
type: PARAGRAPH,
children: [{
type: LINK,
title: null,
url: '#' + node.id,
children: [{
type: TEXT,
value: node.value
}]
}]
});

children.push(item);
} else if (last && last.type === LIST_ITEM) {
insert(node, last, tight);
} else if (last && last.type === LIST) {
node.depth--;

insert(node, last);
} else if (parent.type === LIST) {
item = listItem();

insert(node, item);

children.push(item);
} else {
item = list();
node.depth--;

insert(node, item);

children.push(item);
}

/*
* Properly style list-items with new lines.
*/

if (parent.type === LIST_ITEM) {
parent.loose = tight ? false : children.length > 1;
} else {
if (tight) {
isLoose = false;
} else {
index = -1;

while (++index < length) {
if (children[index].loose) {
isLoose = true;

break;
}
}
}

index = -1;

while (++index < length) {
children[index].loose = isLoose;
}
}
}
Loading