mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Add synchronous version of the API, with tests and documentation.
This commit is contained in:
parent
200dddf3d1
commit
e557f3a97f
6 changed files with 132 additions and 18 deletions
|
@ -87,7 +87,7 @@
|
||||||
"no-space-before-semi": 2,
|
"no-space-before-semi": 2,
|
||||||
"no-spaced-func": 2,
|
"no-spaced-func": 2,
|
||||||
"no-sparse-arrays": 2,
|
"no-sparse-arrays": 2,
|
||||||
"no-sync": 2,
|
"no-sync": 0,
|
||||||
"no-ternary": 0,
|
"no-ternary": 0,
|
||||||
"no-trailing-spaces": 2,
|
"no-trailing-spaces": 2,
|
||||||
"no-throw-literal": 2,
|
"no-throw-literal": 2,
|
||||||
|
|
40
README.md
40
README.md
|
@ -87,6 +87,8 @@ See [Rules.md](doc/Rules.md) for more details.
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
Standard asynchronous interface:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
/**
|
||||||
* Lint specified Markdown files according to configurable rules.
|
* Lint specified Markdown files according to configurable rules.
|
||||||
|
@ -98,6 +100,18 @@ See [Rules.md](doc/Rules.md) for more details.
|
||||||
function markdownlint(options, callback) { ... }
|
function markdownlint(options, callback) { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Synchronous interface (for build scripts, etc.):
|
||||||
|
|
||||||
|
```js
|
||||||
|
/**
|
||||||
|
* Lint specified Markdown files according to configurable rules.
|
||||||
|
*
|
||||||
|
* @param {Object} options Configuration options.
|
||||||
|
* @returns {Object} Result object.
|
||||||
|
*/
|
||||||
|
function markdownlint.sync(options) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
### options
|
### options
|
||||||
|
|
||||||
Type: `Object`
|
Type: `Object`
|
||||||
|
@ -161,9 +175,14 @@ See the [style](style) directory for more samples.
|
||||||
|
|
||||||
Type: `Function` taking (`Error`, `Object`)
|
Type: `Function` taking (`Error`, `Object`)
|
||||||
|
|
||||||
Function to call upon completion.
|
Standard completion callback.
|
||||||
|
|
||||||
See below for an example of the structure of the `result` object.
|
### result
|
||||||
|
|
||||||
|
Type: `Object`
|
||||||
|
|
||||||
|
Call `result.toString()` for convenience or see below for an example of the
|
||||||
|
structure of the `result` object.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -183,7 +202,14 @@ markdownlint(options, function callback(err, result) {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Outputs:
|
Or invoke `markdownlint.sync` for a synchronous call:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var result = markdownlint.sync(options);
|
||||||
|
console.log(result.toString());
|
||||||
|
```
|
||||||
|
|
||||||
|
Output of both calls:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
bad.md: 3: MD010 Hard tabs
|
bad.md: 3: MD010 Hard tabs
|
||||||
|
@ -191,7 +217,7 @@ bad.md: 1: MD018 No space after hash on atx style header
|
||||||
bad.md: 3: MD018 No space after hash on atx style header
|
bad.md: 3: MD018 No space after hash on atx style header
|
||||||
```
|
```
|
||||||
|
|
||||||
Or examine the `result` object directly:
|
To examine the `result` object directly:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
markdownlint(options, function callback(err, result) {
|
markdownlint(options, function callback(err, result) {
|
||||||
|
@ -201,7 +227,7 @@ markdownlint(options, function callback(err, result) {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Outputs:
|
Output:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -236,7 +262,7 @@ gulp.task("markdownlint", function task() {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Outputs:
|
Output:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
[00:00:00] Starting 'markdownlint'...
|
[00:00:00] Starting 'markdownlint'...
|
||||||
|
@ -275,7 +301,7 @@ module.exports = function wrapper(grunt) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Outputs:
|
Output:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Running "markdownlint:example" (markdownlint) task
|
Running "markdownlint:example" (markdownlint) task
|
||||||
|
|
|
@ -19,3 +19,7 @@ markdownlint(options, function callback(err, result) {
|
||||||
console.dir(result, { "colors": true });
|
console.dir(result, { "colors": true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Make a synchronous call
|
||||||
|
var result = markdownlint.sync(options);
|
||||||
|
console.log(result.toString());
|
||||||
|
|
|
@ -54,8 +54,9 @@ function uniqueFilterForSorted(value, index, array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lints a single file
|
// Lints a single file
|
||||||
function lintFile(file, config, callback) {
|
function lintFile(file, config, synchronous, callback) {
|
||||||
fs.readFile(file, shared.utf8Encoding, function readFile(err, contents) {
|
// Callback for read file API
|
||||||
|
function readFile(err, contents) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,28 +119,43 @@ function lintFile(file, config, callback) {
|
||||||
});
|
});
|
||||||
callback(null, result);
|
callback(null, result);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
// Make a/synchronous call to read file
|
||||||
|
if (synchronous) {
|
||||||
|
readFile(null, fs.readFileSync(file, shared.utf8Encoding));
|
||||||
|
} else {
|
||||||
|
fs.readFile(file, shared.utf8Encoding, readFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback used as a sentinel by markdownlintSync
|
||||||
|
function markdownlintSynchronousCallback() {
|
||||||
|
// Unreachable; no code path in the synchronous case passes err
|
||||||
|
// if (err) {
|
||||||
|
// throw err; // Synchronous APIs throw
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lint specified Markdown files according to configurable rules.
|
* Lint specified Markdown files according to configurable rules.
|
||||||
*
|
*
|
||||||
* @param {Object} options Configuration options.
|
* @param {Object} options Configuration options.
|
||||||
* @param {Function} callback Callback (err, results) function.
|
* @param {Function} callback Callback (err, result) function.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
module.exports = function markdownlint(options, callback) {
|
function markdownlint(options, callback) {
|
||||||
// Normalize inputs
|
// Normalize inputs
|
||||||
options = options || {};
|
options = options || {};
|
||||||
callback = callback || function noop() {};
|
callback = callback || function noop() {};
|
||||||
var files = (options.files || []).slice();
|
var files = (options.files || []).slice();
|
||||||
var config = options.config || { "default": true };
|
var config = options.config || { "default": true };
|
||||||
|
var synchronous = (callback === markdownlintSynchronousCallback);
|
||||||
var results = new Results();
|
var results = new Results();
|
||||||
// Lint each input file
|
// Lint each input file
|
||||||
function lintFiles() {
|
function lintFiles() {
|
||||||
var file = files.shift();
|
var file = files.shift();
|
||||||
if (file) {
|
if (file) {
|
||||||
lintFile(file, config, function lintFileCallback(err, result) {
|
lintFile(file, config, synchronous, function lintedFile(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -153,4 +169,21 @@ module.exports = function markdownlint(options, callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lintFiles();
|
lintFiles();
|
||||||
};
|
if (synchronous) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lint specified Markdown files according to configurable rules.
|
||||||
|
*
|
||||||
|
* @param {Object} options Configuration options.
|
||||||
|
* @returns {Object} Result object.
|
||||||
|
*/
|
||||||
|
function markdownlintSync(options) {
|
||||||
|
return markdownlint(options, markdownlintSynchronousCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export a/synchronous APIs
|
||||||
|
module.exports = markdownlint;
|
||||||
|
module.exports.sync = markdownlintSync;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
"test": "nodeunit",
|
"test": "nodeunit",
|
||||||
"test-cover": "istanbul cover node_modules/nodeunit/bin/nodeunit",
|
"test-cover": "istanbul cover node_modules/nodeunit/bin/nodeunit",
|
||||||
"debug": "node debug node_modules/nodeunit/bin/nodeunit",
|
"debug": "node debug node_modules/nodeunit/bin/nodeunit",
|
||||||
"lint": "eslint lib test & eslint --rule \"no-console: 0\" example",
|
"lint": "eslint lib test & eslint --rule \"no-console: 0, no-shadow: 0\" example",
|
||||||
"example": "cd example & node standalone.js & grunt markdownlint & gulp markdownlint"
|
"example": "cd example & node standalone.js & grunt markdownlint & gulp markdownlint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -65,7 +65,7 @@ function createTestForFile(file) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readdirSync("./test").forEach(function forFile(file) { // eslint-disable-line
|
fs.readdirSync("./test").forEach(function forFile(file) {
|
||||||
if (file.match(/\.md$/)) {
|
if (file.match(/\.md$/)) {
|
||||||
module.exports[file] = createTestForFile(path.join("./test", file));
|
module.exports[file] = createTestForFile(path.join("./test", file));
|
||||||
}
|
}
|
||||||
|
@ -122,6 +122,42 @@ module.exports.resultFormatting = function resultFormatting(test) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.resultFormattingSync = function resultFormattingSync(test) {
|
||||||
|
test.expect(2);
|
||||||
|
var options = {
|
||||||
|
"files": [
|
||||||
|
"./test/atx_header_spacing.md",
|
||||||
|
"./test/first_header_bad_atx.md"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
var actualResult = markdownlint.sync(options);
|
||||||
|
var expectedResult = {
|
||||||
|
"./test/atx_header_spacing.md": {
|
||||||
|
"MD002": [ 3 ],
|
||||||
|
"MD018": [ 1 ],
|
||||||
|
"MD019": [ 3, 5 ]
|
||||||
|
},
|
||||||
|
"./test/first_header_bad_atx.md": {
|
||||||
|
"MD002": [ 1 ]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
test.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
||||||
|
var actualMessage = actualResult.toString();
|
||||||
|
var expectedMessage =
|
||||||
|
"./test/atx_header_spacing.md: 3: MD002" +
|
||||||
|
" First header should be a h1 header\n" +
|
||||||
|
"./test/atx_header_spacing.md: 1: MD018" +
|
||||||
|
" No space after hash on atx style header\n" +
|
||||||
|
"./test/atx_header_spacing.md: 3: MD019" +
|
||||||
|
" Multiple spaces after hash on atx style header\n" +
|
||||||
|
"./test/atx_header_spacing.md: 5: MD019" +
|
||||||
|
" Multiple spaces after hash on atx style header\n" +
|
||||||
|
"./test/first_header_bad_atx.md: 1: MD002" +
|
||||||
|
" First header should be a h1 header";
|
||||||
|
test.equal(actualMessage, expectedMessage, "Incorrect message.");
|
||||||
|
test.done();
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.defaultTrue = function defaultTrue(test) {
|
module.exports.defaultTrue = function defaultTrue(test) {
|
||||||
test.expect(2);
|
test.expect(2);
|
||||||
var options = {
|
var options = {
|
||||||
|
@ -435,17 +471,32 @@ module.exports.missingCallback = function missingCallback(test) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.badFile = function badFile(test) {
|
module.exports.badFile = function badFile(test) {
|
||||||
test.expect(3);
|
test.expect(4);
|
||||||
markdownlint({
|
markdownlint({
|
||||||
"files": [ "./badFile" ]
|
"files": [ "./badFile" ]
|
||||||
}, function callback(err, result) {
|
}, function callback(err, result) {
|
||||||
test.ok(err, "Did not get an error for bad file.");
|
test.ok(err, "Did not get an error for bad file.");
|
||||||
|
test.ok(err instanceof Error, "Error not instance of Error.");
|
||||||
test.equal(err.code, "ENOENT", "Error code for bad file not ENOENT.");
|
test.equal(err.code, "ENOENT", "Error code for bad file not ENOENT.");
|
||||||
test.ok(!result, "Got result for bad file.");
|
test.ok(!result, "Got result for bad file.");
|
||||||
test.done();
|
test.done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.badFileSync = function badFileSync(test) {
|
||||||
|
test.expect(3);
|
||||||
|
test.throws(function badFileCall() {
|
||||||
|
markdownlint.sync({
|
||||||
|
"files": [ "./badFile" ]
|
||||||
|
});
|
||||||
|
}, function testError(err) {
|
||||||
|
test.ok(err instanceof Error, "Error not instance of Error.");
|
||||||
|
test.equal(err.code, "ENOENT", "Error code for bad file not ENOENT.");
|
||||||
|
return true;
|
||||||
|
}, "Did not get exception for bad file.");
|
||||||
|
test.done();
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.readme = function readme(test) {
|
module.exports.readme = function readme(test) {
|
||||||
test.expect(143);
|
test.expect(143);
|
||||||
fs.readFile("README.md", shared.utf8Encoding,
|
fs.readFile("README.md", shared.utf8Encoding,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue