remark-lint/packages/remark-lint-fenced-code-marker/index.js

108 lines
2.3 KiB
JavaScript
Raw Normal View History

2015-06-02 09:34:14 +03:00
/**
* @author Titus Wormer
2015-08-17 14:48:19 +03:00
* @copyright 2015 Titus Wormer
* @license MIT
2015-06-02 09:34:14 +03:00
* @module fenced-code-marker
* @fileoverview
* Warn for violating fenced code markers.
*
* Options: `` '`' ``, `'~'`, or `'consistent'`, default: `'consistent'`.
2015-06-02 09:34:14 +03:00
*
* `'consistent'` detects the first used fenced code marker style and warns
* when subsequent fenced code-blocks use different styles.
*
* @example {"name": "valid.md"}
*
* Indented code blocks are not affected by this rule:
*
* bravo();
*
* @example {"name": "valid.md", "setting": "`"}
*
* ```alpha
* bravo();
2015-08-17 14:57:43 +03:00
* ```
2015-06-02 09:34:14 +03:00
*
2015-08-17 14:57:43 +03:00
* ```
* charlie();
2015-08-17 14:57:43 +03:00
* ```
2015-06-02 09:34:14 +03:00
*
* @example {"name": "valid.md", "setting": "~"}
*
* ~~~alpha
* bravo();
2015-08-17 14:57:43 +03:00
* ~~~
2015-06-02 09:34:14 +03:00
*
2015-08-17 14:57:43 +03:00
* ~~~
* charlie();
2015-08-17 14:57:43 +03:00
* ~~~
2015-06-02 09:34:14 +03:00
*
* @example {"name": "invalid.md", "label": "input"}
2015-06-02 09:34:14 +03:00
*
* ```alpha
* bravo();
2015-08-17 14:57:43 +03:00
* ```
*
* ~~~
* charlie();
* ~~~
*
* @example {"name": "invalid.md", "label": "output"}
*
* 5:1-7:4: Fenced code should use ` as a marker
*
* @example {"name": "invalid.md", "setting": "!", "label": "output", "config": {"positionless": true}}
*
* 1:1: Invalid fenced code marker `!`: use either `'consistent'`, `` '`' ``, or `'~'`
2015-06-02 09:34:14 +03:00
*/
'use strict';
var rule = require('unified-lint-rule');
var visit = require('unist-util-visit');
2016-08-01 19:09:58 +03:00
var position = require('unist-util-position');
var generated = require('unist-util-generated');
2015-06-02 09:34:14 +03:00
module.exports = rule('remark-lint:fenced-code-marker', fencedCodeMarker);
2015-06-02 09:34:14 +03:00
var MARKERS = {
2016-08-01 21:41:43 +03:00
'`': true,
'~': true,
2016-10-11 12:47:14 +03:00
null: true
2015-06-02 09:34:14 +03:00
};
2016-08-01 21:41:43 +03:00
function fencedCodeMarker(ast, file, preferred) {
var contents = file.toString();
2015-06-02 09:34:14 +03:00
2016-08-01 21:41:43 +03:00
preferred = typeof preferred !== 'string' || preferred === 'consistent' ? null : preferred;
2015-06-02 09:34:14 +03:00
2016-08-01 21:41:43 +03:00
if (MARKERS[preferred] !== true) {
file.fail('Invalid fenced code marker `' + preferred + '`: use either `\'consistent\'`, `` \'`\' ``, or `\'~\'`');
}
2015-06-02 09:34:14 +03:00
visit(ast, 'code', visitor);
function visitor(node) {
2016-08-01 21:41:43 +03:00
var marker = contents.substr(position.start(node).offset, 4);
2015-06-02 09:34:14 +03:00
if (generated(node)) {
2016-08-01 21:41:43 +03:00
return;
}
2015-06-02 09:34:14 +03:00
2016-08-01 21:41:43 +03:00
marker = marker.trimLeft().charAt(0);
2015-06-02 09:34:14 +03:00
2016-08-01 21:41:43 +03:00
/* Ignore unfenced code blocks. */
if (MARKERS[marker] !== true) {
return;
}
2015-06-02 09:34:14 +03:00
2016-08-01 21:41:43 +03:00
if (preferred) {
if (marker !== preferred) {
2016-08-22 00:46:21 +03:00
file.message('Fenced code should use ' + preferred + ' as a marker', node);
2016-08-01 21:41:43 +03:00
}
} else {
preferred = marker;
}
}
2015-06-02 09:34:14 +03:00
}