mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-17 06:20:12 +01:00
Support tilde paths ("~" prefix) in readConfig/Sync APIs (for "file" parameter and "extends" keys).
This commit is contained in:
parent
5505deb1c9
commit
ffc4d56918
6 changed files with 132 additions and 31 deletions
|
|
@ -639,7 +639,8 @@ The `file` is resolved relative to the current working directory. If an `extends
|
||||||
key is present once read, its value will be resolved as a path relative to `file`
|
key is present once read, its value will be resolved as a path relative to `file`
|
||||||
and loaded recursively. Settings from a file referenced by `extends` are applied
|
and loaded recursively. Settings from a file referenced by `extends` are applied
|
||||||
first, then those of `file` are applied on top (overriding any of the same keys
|
first, then those of `file` are applied on top (overriding any of the same keys
|
||||||
appearing in the referenced file).
|
appearing in the referenced file). If either the `file` or `extends` path begins
|
||||||
|
with the `~` directory, it will act as a placeholder for the home directory.
|
||||||
|
|
||||||
#### parsers
|
#### parsers
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -995,6 +995,18 @@ function deepFreeze(obj) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
module.exports.deepFreeze = deepFreeze;
|
module.exports.deepFreeze = deepFreeze;
|
||||||
|
/**
|
||||||
|
* Expands a path with a tilde to an absolute path.
|
||||||
|
*
|
||||||
|
* @param {string} file Path that may begin with a tilde.
|
||||||
|
* @param {Object} os Node.js "os" module.
|
||||||
|
* @returns {string} Absolute path (or original path).
|
||||||
|
*/
|
||||||
|
function expandTildePath(file, os) {
|
||||||
|
var homedir = os && os.homedir();
|
||||||
|
return homedir ? file.replace(/^~($|\/|\\)/, "".concat(homedir, "$1")) : file;
|
||||||
|
}
|
||||||
|
module.exports.expandTildePath = expandTildePath;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
@ -1030,6 +1042,16 @@ module.exports = markdownit;
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "?a32b":
|
||||||
|
/*!********************!*\
|
||||||
|
!*** os (ignored) ***!
|
||||||
|
\********************/
|
||||||
|
/***/ (() => {
|
||||||
|
|
||||||
|
/* (ignored) */
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ "?b85c":
|
/***/ "?b85c":
|
||||||
/*!**********************!*\
|
/*!**********************!*\
|
||||||
!*** path (ignored) ***!
|
!*** path (ignored) ***!
|
||||||
|
|
@ -2070,6 +2092,8 @@ function readConfig(file, parsers, fs, callback) {
|
||||||
fs = __webpack_require__(/*! fs */ "?ec0a");
|
fs = __webpack_require__(/*! fs */ "?ec0a");
|
||||||
}
|
}
|
||||||
// Read file
|
// Read file
|
||||||
|
var os = __webpack_require__(/*! os */ "?a32b");
|
||||||
|
file = helpers.expandTildePath(file, os);
|
||||||
fs.readFile(file, "utf8", function (err, content) {
|
fs.readFile(file, "utf8", function (err, content) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
@ -2084,7 +2108,7 @@ function readConfig(file, parsers, fs, callback) {
|
||||||
var configExtends = config.extends;
|
var configExtends = config.extends;
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
return resolveConfigExtends(file, configExtends, fs, function (_, resolvedExtends) { return readConfig(resolvedExtends, parsers, fs, function (errr, extendsConfig) {
|
return resolveConfigExtends(file, helpers.expandTildePath(configExtends, os), fs, function (_, resolvedExtends) { return readConfig(resolvedExtends, parsers, fs, function (errr, extendsConfig) {
|
||||||
if (errr) {
|
if (errr) {
|
||||||
return callback(errr);
|
return callback(errr);
|
||||||
}
|
}
|
||||||
|
|
@ -2121,6 +2145,8 @@ function readConfigSync(file, parsers, fs) {
|
||||||
fs = __webpack_require__(/*! fs */ "?ec0a");
|
fs = __webpack_require__(/*! fs */ "?ec0a");
|
||||||
}
|
}
|
||||||
// Read file
|
// Read file
|
||||||
|
var os = __webpack_require__(/*! os */ "?a32b");
|
||||||
|
file = helpers.expandTildePath(file, os);
|
||||||
var content = fs.readFileSync(file, "utf8");
|
var content = fs.readFileSync(file, "utf8");
|
||||||
// Try to parse file
|
// Try to parse file
|
||||||
var _a = parseConfiguration(file, content, parsers), config = _a.config, message = _a.message;
|
var _a = parseConfiguration(file, content, parsers), config = _a.config, message = _a.message;
|
||||||
|
|
@ -2131,7 +2157,7 @@ function readConfigSync(file, parsers, fs) {
|
||||||
var configExtends = config.extends;
|
var configExtends = config.extends;
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
var resolvedExtends = resolveConfigExtendsSync(file, configExtends, fs);
|
var resolvedExtends = resolveConfigExtendsSync(file, helpers.expandTildePath(configExtends, os), fs);
|
||||||
return __assign(__assign({}, readConfigSync(resolvedExtends, parsers, fs)), config);
|
return __assign(__assign({}, readConfigSync(resolvedExtends, parsers, fs)), config);
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
|
|
|
||||||
|
|
@ -1021,3 +1021,16 @@ function deepFreeze(obj) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
module.exports.deepFreeze = deepFreeze;
|
module.exports.deepFreeze = deepFreeze;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands a path with a tilde to an absolute path.
|
||||||
|
*
|
||||||
|
* @param {string} file Path that may begin with a tilde.
|
||||||
|
* @param {Object} os Node.js "os" module.
|
||||||
|
* @returns {string} Absolute path (or original path).
|
||||||
|
*/
|
||||||
|
function expandTildePath(file, os) {
|
||||||
|
const homedir = os && os.homedir();
|
||||||
|
return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file;
|
||||||
|
}
|
||||||
|
module.exports.expandTildePath = expandTildePath;
|
||||||
|
|
|
||||||
|
|
@ -1026,6 +1026,8 @@ function readConfig(file, parsers, fs, callback) {
|
||||||
fs = require("fs");
|
fs = require("fs");
|
||||||
}
|
}
|
||||||
// Read file
|
// Read file
|
||||||
|
const os = require("os");
|
||||||
|
file = helpers.expandTildePath(file, os);
|
||||||
fs.readFile(file, "utf8", (err, content) => {
|
fs.readFile(file, "utf8", (err, content) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
@ -1042,7 +1044,7 @@ function readConfig(file, parsers, fs, callback) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
return resolveConfigExtends(
|
return resolveConfigExtends(
|
||||||
file,
|
file,
|
||||||
configExtends,
|
helpers.expandTildePath(configExtends, os),
|
||||||
fs,
|
fs,
|
||||||
(_, resolvedExtends) => readConfig(
|
(_, resolvedExtends) => readConfig(
|
||||||
resolvedExtends,
|
resolvedExtends,
|
||||||
|
|
@ -1093,6 +1095,8 @@ function readConfigSync(file, parsers, fs) {
|
||||||
fs = require("fs");
|
fs = require("fs");
|
||||||
}
|
}
|
||||||
// Read file
|
// Read file
|
||||||
|
const os = require("os");
|
||||||
|
file = helpers.expandTildePath(file, os);
|
||||||
const content = fs.readFileSync(file, "utf8");
|
const content = fs.readFileSync(file, "utf8");
|
||||||
// Try to parse file
|
// Try to parse file
|
||||||
const { config, message } = parseConfiguration(file, content, parsers);
|
const { config, message } = parseConfiguration(file, content, parsers);
|
||||||
|
|
@ -1103,7 +1107,11 @@ function readConfigSync(file, parsers, fs) {
|
||||||
const configExtends = config.extends;
|
const configExtends = config.extends;
|
||||||
if (configExtends) {
|
if (configExtends) {
|
||||||
delete config.extends;
|
delete config.extends;
|
||||||
const resolvedExtends = resolveConfigExtendsSync(file, configExtends, fs);
|
const resolvedExtends = resolveConfigExtendsSync(
|
||||||
|
file,
|
||||||
|
helpers.expandTildePath(configExtends, os),
|
||||||
|
fs
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
...readConfigSync(resolvedExtends, parsers, fs),
|
...readConfigSync(resolvedExtends, parsers, fs),
|
||||||
...config
|
...config
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const os = require("os");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const test = require("ava").default;
|
const test = require("ava").default;
|
||||||
const markdownlint = require("../lib/markdownlint");
|
const markdownlint = require("../lib/markdownlint");
|
||||||
|
|
||||||
|
const sameFileSystem = (path.relative(os.homedir(), __dirname) !== __dirname);
|
||||||
|
|
||||||
test.cb("configSingle", (t) => {
|
test.cb("configSingle", (t) => {
|
||||||
t.plan(2);
|
t.plan(2);
|
||||||
markdownlint.readConfig("./test/config/config-child.json",
|
markdownlint.readConfig("./test/config/config-child.json",
|
||||||
|
|
@ -28,6 +31,20 @@ test.cb("configAbsolute", (t) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (sameFileSystem) {
|
||||||
|
test.cb("configTilde", (t) => {
|
||||||
|
t.plan(2);
|
||||||
|
markdownlint.readConfig(
|
||||||
|
`~/${path.relative(os.homedir(), "./test/config/config-child.json")}`,
|
||||||
|
function callback(err, actual) {
|
||||||
|
t.falsy(err);
|
||||||
|
const expected = require("./config/config-child.json");
|
||||||
|
t.deepEqual(actual, expected, "Config object not correct.");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
test.cb("configMultiple", (t) => {
|
test.cb("configMultiple", (t) => {
|
||||||
t.plan(2);
|
t.plan(2);
|
||||||
markdownlint.readConfig("./test/config/config-grandparent.json",
|
markdownlint.readConfig("./test/config/config-grandparent.json",
|
||||||
|
|
@ -60,9 +77,10 @@ test.cb("configMultipleWithRequireResolve", (t) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test.cb("configCustomFileSystem", (t) => {
|
test.cb("configCustomFileSystem", (t) => {
|
||||||
t.plan(5);
|
t.plan(3);
|
||||||
const file = path.resolve("/dir/file.json");
|
const file = "/dir/file.json";
|
||||||
const extended = path.resolve("/dir/extended.json");
|
const extended = "~/dir/extended.json";
|
||||||
|
const expanded = path.join(os.homedir(), extended.slice(1));
|
||||||
const fileContent = {
|
const fileContent = {
|
||||||
"extends": extended,
|
"extends": extended,
|
||||||
"default": true,
|
"default": true,
|
||||||
|
|
@ -74,20 +92,16 @@ test.cb("configCustomFileSystem", (t) => {
|
||||||
};
|
};
|
||||||
const fsApi = {
|
const fsApi = {
|
||||||
"access": (p, m, cb) => {
|
"access": (p, m, cb) => {
|
||||||
t.is(p, extended);
|
t.is(p, expanded);
|
||||||
return (cb || m)();
|
return (cb || m)();
|
||||||
},
|
},
|
||||||
"readFile": (p, o, cb) => {
|
"readFile": (p, o, cb) => {
|
||||||
switch (p) {
|
if (p === file) {
|
||||||
case file:
|
|
||||||
t.is(p, file);
|
|
||||||
return cb(null, JSON.stringify(fileContent));
|
return cb(null, JSON.stringify(fileContent));
|
||||||
case extended:
|
} else if (p === expanded) {
|
||||||
t.is(p, extended);
|
|
||||||
return cb(null, JSON.stringify(extendedContent));
|
return cb(null, JSON.stringify(extendedContent));
|
||||||
default:
|
|
||||||
return t.fail();
|
|
||||||
}
|
}
|
||||||
|
return t.fail(p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
markdownlint.readConfig(
|
markdownlint.readConfig(
|
||||||
|
|
@ -254,6 +268,16 @@ test("configAbsoluteSync", (t) => {
|
||||||
t.deepEqual(actual, expected, "Config object not correct.");
|
t.deepEqual(actual, expected, "Config object not correct.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (sameFileSystem) {
|
||||||
|
test("configTildeSync", (t) => {
|
||||||
|
t.plan(1);
|
||||||
|
const actual = markdownlint.readConfigSync(
|
||||||
|
`~/${path.relative(os.homedir(), "./test/config/config-child.json")}`);
|
||||||
|
const expected = require("./config/config-child.json");
|
||||||
|
t.deepEqual(actual, expected, "Config object not correct.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
test("configMultipleSync", (t) => {
|
test("configMultipleSync", (t) => {
|
||||||
t.plan(1);
|
t.plan(1);
|
||||||
const actual =
|
const actual =
|
||||||
|
|
@ -362,9 +386,10 @@ test("configMultipleHybridSync", (t) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("configCustomFileSystemSync", (t) => {
|
test("configCustomFileSystemSync", (t) => {
|
||||||
t.plan(4);
|
t.plan(2);
|
||||||
const file = path.resolve("/dir/file.json");
|
const file = "/dir/file.json";
|
||||||
const extended = path.resolve("/dir/extended.json");
|
const extended = "~/dir/extended.json";
|
||||||
|
const expanded = path.join(os.homedir(), extended.slice(1));
|
||||||
const fileContent = {
|
const fileContent = {
|
||||||
"extends": extended,
|
"extends": extended,
|
||||||
"default": true,
|
"default": true,
|
||||||
|
|
@ -376,19 +401,15 @@ test("configCustomFileSystemSync", (t) => {
|
||||||
};
|
};
|
||||||
const fsApi = {
|
const fsApi = {
|
||||||
"accessSync": (p) => {
|
"accessSync": (p) => {
|
||||||
t.is(p, extended);
|
t.is(p, expanded);
|
||||||
},
|
},
|
||||||
"readFileSync": (p) => {
|
"readFileSync": (p) => {
|
||||||
switch (p) {
|
if (p === file) {
|
||||||
case file:
|
|
||||||
t.is(p, file);
|
|
||||||
return JSON.stringify(fileContent);
|
return JSON.stringify(fileContent);
|
||||||
case extended:
|
} else if (p === expanded) {
|
||||||
t.is(p, extended);
|
|
||||||
return JSON.stringify(extendedContent);
|
return JSON.stringify(extendedContent);
|
||||||
default:
|
|
||||||
return t.fail();
|
|
||||||
}
|
}
|
||||||
|
return t.fail(p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const actual = markdownlint.readConfigSync(file, null, fsApi);
|
const actual = markdownlint.readConfigSync(file, null, fsApi);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const os = require("os");
|
||||||
|
const path = require("path");
|
||||||
const test = require("ava").default;
|
const test = require("ava").default;
|
||||||
const helpers = require("../helpers");
|
const helpers = require("../helpers");
|
||||||
|
|
||||||
|
|
@ -1303,3 +1305,33 @@ test("htmlElementRanges", (t) => {
|
||||||
const actual = helpers.htmlElementRanges(params, lineMetadata);
|
const actual = helpers.htmlElementRanges(params, lineMetadata);
|
||||||
t.deepEqual(actual, expected);
|
t.deepEqual(actual, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("expandTildePath", (t) => {
|
||||||
|
t.plan(16);
|
||||||
|
const homedir = os.homedir();
|
||||||
|
t.is(helpers.expandTildePath("", os), "");
|
||||||
|
t.is(helpers.expandTildePath("", null), "");
|
||||||
|
t.is(
|
||||||
|
path.resolve(helpers.expandTildePath("~", os)),
|
||||||
|
homedir
|
||||||
|
);
|
||||||
|
t.is(helpers.expandTildePath("~", null), "~");
|
||||||
|
t.is(helpers.expandTildePath("file", os), "file");
|
||||||
|
t.is(helpers.expandTildePath("file", null), "file");
|
||||||
|
t.is(helpers.expandTildePath("/file", os), "/file");
|
||||||
|
t.is(helpers.expandTildePath("/file", null), "/file");
|
||||||
|
t.is(
|
||||||
|
path.resolve(helpers.expandTildePath("~/file", os)),
|
||||||
|
path.join(homedir, "/file")
|
||||||
|
);
|
||||||
|
t.is(helpers.expandTildePath("~/file", null), "~/file");
|
||||||
|
t.is(helpers.expandTildePath("dir/file", os), "dir/file");
|
||||||
|
t.is(helpers.expandTildePath("dir/file", null), "dir/file");
|
||||||
|
t.is(helpers.expandTildePath("/dir/file", os), "/dir/file");
|
||||||
|
t.is(helpers.expandTildePath("/dir/file", null), "/dir/file");
|
||||||
|
t.is(
|
||||||
|
path.resolve(helpers.expandTildePath("~/dir/file", os)),
|
||||||
|
path.join(homedir, "/dir/file")
|
||||||
|
);
|
||||||
|
t.is(helpers.expandTildePath("~/dir/file", null), "~/dir/file");
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue