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

Use require.resolve as a fallback of path.resolve #342

Merged
merged 16 commits into from
Oct 22, 2020
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 2 additions & 2 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
- name: Install Dependencies
run: npm install --no-package-lock
- name: Run All Validations
if: ${{ matrix.node-version != '10.x' }}
if: ${{ matrix.node-version == '14.x' }}
run: npm run ci
- name: Run Tests Only
if: ${{ matrix.node-version == '10.x' }}
if: ${{ matrix.node-version != '14.x' }}
run: npm run test
42 changes: 36 additions & 6 deletions lib/markdownlint.js
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,38 @@ function parseConfiguration(name, content, parsers) {
};
}

/**
* Resolve referenced "extends" path in a configuration file
* using path.resolve() and require.resolve() as a fallback.
*
* @param {string} configFile Configuration file name.
* @param {string} referenceId Referenced identifier to resolve.
* @returns {string} Resolved path to file
kachkaev marked this conversation as resolved.
Show resolved Hide resolved
*/
function resolveConfigExtends(configFile, referenceId) {
const configFileDirname = path.dirname(configFile);
const resolvedExtendsFile = path.resolve(configFileDirname, referenceId);

try {
if (fs.statSync(resolvedExtendsFile).isFile()) {
DavidAnson marked this conversation as resolved.
Show resolved Hide resolved
kachkaev marked this conversation as resolved.
Show resolved Hide resolved
return resolvedExtendsFile;
}
// eslint-disable-next-line unicorn/prefer-optional-catch-binding
kachkaev marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
// If fs.statSync has thrown, trying require.resolve
}

try {
return require.resolve(referenceId, { "paths": [ configFileDirname ] });

// eslint-disable-next-line unicorn/prefer-optional-catch-binding
} catch (error) {
DavidAnson marked this conversation as resolved.
Show resolved Hide resolved
// If require.resolve throws, returning resolvedExtendsFile for BC
}

kachkaev marked this conversation as resolved.
Show resolved Hide resolved
return resolvedExtendsFile;
}

/**
* Read specified configuration file.
*
Expand Down Expand Up @@ -925,8 +957,8 @@ function readConfig(file, parsers, callback) {
const configExtends = config.extends;
kachkaev marked this conversation as resolved.
Show resolved Hide resolved
if (configExtends) {
delete config.extends;
const extendsFile = path.resolve(path.dirname(file), configExtends);
return readConfig(extendsFile, parsers, (errr, extendsConfig) => {
const resolvedExtends = resolveConfigExtends(file, configExtends);
return readConfig(resolvedExtends, parsers, (errr, extendsConfig) => {
if (errr) {
return callback(errr);
}
Expand Down Expand Up @@ -974,11 +1006,9 @@ function readConfigSync(file, parsers) {
const configExtends = config.extends;
if (configExtends) {
delete config.extends;
const resolvedExtends = resolveConfigExtends(file, configExtends);
return {
...readConfigSync(
path.resolve(path.dirname(file), configExtends),
parsers
),
...readConfigSync(resolvedExtends, parsers),
...config
};
}
Expand Down
4 changes: 4 additions & 0 deletions test/config/config-badchildpackage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "@oops/markdownlint-config",
"default": true
}
7 changes: 7 additions & 0 deletions test/config/config-packageparent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "test",
"MD003": false,
"MD007": { "indent": 4 },
"no-hard-tabs": true,
"line-length": { "line_length": 200 }
}
4 changes: 4 additions & 0 deletions test/config/pseudo-package/config-frompackage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"no-hard-tabs": false,
"whitespace": false
}
3 changes: 3 additions & 0 deletions test/config/pseudo-package/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"main": "config-frompackage.json"
}
44 changes: 44 additions & 0 deletions test/markdownlint-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,36 @@ tape("configMultiple", (test) => {
});
});

tape("configMultipleWithRequireResolve", (test) => {
test.plan(2);

try {
fs.symlinkSync(
path.resolve(__dirname, "./config/pseudo-package"),
path.resolve(__dirname, "../node_modules/test"),
kachkaev marked this conversation as resolved.
Show resolved Hide resolved
"dir"
);
// eslint-disable-next-line unicorn/prefer-optional-catch-binding
} catch (error) {
// Package symlink creation failed due to earlier failure
}

markdownlint.readConfig("./test/config/config-packageparent.json",
function callback(err, actual) {
test.ifError(err);
const expected = {
...require("./config/pseudo-package/config-frompackage.json"),
...require("./config/config-packageparent.json")
};
delete expected.extends;
test.deepEqual(actual, expected, "Config object not correct.");

fs.unlinkSync(path.resolve(__dirname, "../node_modules/test"));

test.end();
});
});

tape("configBadFile", (test) => {
test.plan(4);
markdownlint.readConfig("./test/config/config-badfile.json",
Expand Down Expand Up @@ -1059,6 +1089,20 @@ tape("configBadChildFile", (test) => {
});
});

tape("configBadChildPackage", (test) => {
test.plan(4);
markdownlint.readConfig("./test/config/config-badchildpackage.json",
function callback(err, result) {
test.ok(err, "Did not get an error for bad child file.");
test.ok(err instanceof Error, "Error not instance of Error.");
// @ts-ignore
test.equal(err.code, "ENOENT",
DavidAnson marked this conversation as resolved.
Show resolved Hide resolved
"Error code for bad child file not ENOENT.");
test.ok(!result, "Got result for bad child file.");
test.end();
DavidAnson marked this conversation as resolved.
Show resolved Hide resolved
});
});

tape("configBadJson", (test) => {
test.plan(3);
markdownlint.readConfig("./test/config/config-badjson.json",
Expand Down