Skip to content

Commit 53ff5c4

Browse files
committed
Stop using module.createRequire (problematic under webpack), incorporate and export resolveModule helper from markdownlint-cli2.
1 parent a1da464 commit 53ff5c4

16 files changed

+327
-25
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ demo/markdownlint-browser.js
44
demo/markdownlint-browser.min.js
55
node_modules
66
!test/node_modules
7+
!test/rules/node_modules
78
npm-debug.log
89
test-repos
910
.DS_Store

Diff for: lib/defer-require.cjs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @ts-check
2+
3+
"use strict";
4+
5+
/**
6+
* Calls require for markdownit.cjs. Used to synchronously defer loading because module.createRequire is buggy under webpack (https://github.com/webpack/webpack/issues/16724).
7+
*
8+
* @returns {any} Exported module content.
9+
*/
10+
function requireMarkdownItCjs() {
11+
return require("./markdownit.cjs");
12+
}
13+
14+
module.exports = {
15+
requireMarkdownItCjs
16+
};

Diff for: lib/exports.d.mts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { resolveModule } from "./resolve-module.cjs";
12
export type Configuration = import("./markdownlint.mjs").Configuration;
23
export type ConfigurationParser = import("./markdownlint.mjs").ConfigurationParser;
34
export type ConfigurationStrict = import("./markdownlint.mjs").ConfigurationStrict;

Diff for: lib/exports.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @ts-check
22

33
export { applyFix, applyFixes, getVersion } from "./markdownlint.mjs";
4+
export { resolveModule } from "./resolve-module.cjs";
45

56
/** @typedef {import("./markdownlint.mjs").Configuration} Configuration */
67
/** @typedef {import("./markdownlint.mjs").ConfigurationParser} ConfigurationParser */

Diff for: lib/markdownlint.mjs

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// @ts-check
22

33
// @ts-ignore
4-
import { fs as nodeFs, module, os, path } from "#node-imports";
5-
const dynamicRequire = module.createRequire(import.meta.url);
4+
import { fs as nodeFs, os, path } from "#node-imports";
65
import { initialize as cacheInitialize } from "./cache.mjs";
76
import { version } from "./constants.mjs";
7+
import { requireMarkdownItCjs } from "./defer-require.cjs";
8+
import { resolveModule } from "./resolve-module.cjs";
89
import rules from "./rules.mjs";
910
import { parse as micromarkParse } from "./micromark-parse.mjs";
1011
import * as helpers from "../helpers/helpers.cjs";
@@ -501,7 +502,7 @@ function lintContent(
501502
// Parse content into lines and get markdown-it tokens
502503
const lines = content.split(helpers.newLineRe);
503504
const markdownitTokens = needMarkdownItTokens ?
504-
dynamicRequire("./markdownit.cjs").getMarkdownItTokens(markdownItPlugins, preClearedContent, lines) :
505+
requireMarkdownItCjs().getMarkdownItTokens(markdownItPlugins, preClearedContent, lines) :
505506
[];
506507
// Create (frozen) parameters for rules
507508
/** @type {MarkdownParsers} */
@@ -1010,10 +1011,10 @@ function resolveConfigExtends(configFile, referenceId, fs, callback) {
10101011
if (err) {
10111012
// Not a file, try require.resolve
10121013
try {
1013-
return callback(null, dynamicRequire.resolve(
1014-
referenceId,
1015-
{ "paths": [ configFileDirname ] }
1016-
));
1014+
return callback(
1015+
null,
1016+
resolveModule(referenceId, [ configFileDirname ])
1017+
);
10171018
} catch {
10181019
// Unable to resolve, use resolvedExtendsFile
10191020
}
@@ -1041,10 +1042,7 @@ function resolveConfigExtendsSync(configFile, referenceId, fs) {
10411042
// Not a file, try require.resolve
10421043
}
10431044
try {
1044-
return dynamicRequire.resolve(
1045-
referenceId,
1046-
{ "paths": [ configFileDirname ] }
1047-
);
1045+
return resolveModule(referenceId, [ configFileDirname ]);
10481046
} catch {
10491047
// Unable to resolve, return resolvedExtendsFile
10501048
}

Diff for: lib/node-imports-browser-module.cjs

-7
This file was deleted.

Diff for: lib/node-imports-browser.mjs

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ export const fs = {
1212
"readFileSync": throwForSync
1313
};
1414

15-
export { default as module } from "./node-imports-browser-module.cjs";
16-
1715
export const os = {};
1816

1917
export const path = {

Diff for: lib/node-imports-node.mjs

-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
import { access, accessSync, readFile, readFileSync } from "node:fs";
44
export const fs = { access, accessSync, readFile, readFileSync };
55

6-
import { createRequire } from "node:module";
7-
export const module = { createRequire };
8-
96
import { EOL, homedir } from "node:os";
107
export const os = { EOL, homedir };
118

Diff for: lib/resolve-module.cjs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// @ts-check
2+
3+
"use strict";
4+
5+
// @ts-ignore
6+
// eslint-disable-next-line camelcase, no-inline-comments, no-undef
7+
const nativeRequire = (typeof __non_webpack_require__ === "undefined") ? require : /* c8 ignore next */ __non_webpack_require__;
8+
// Captures the native require implementation (even under webpack).
9+
10+
/**
11+
* @typedef RequireResolveOptions
12+
* @property {string[]} [paths] Additional paths to resolve from.
13+
*/
14+
15+
/**
16+
* @callback RequireResolve
17+
* @param {string} id Module name or path.
18+
* @param {RequireResolveOptions} options Options to apply.
19+
* @returns {string} Resolved module path.
20+
*/
21+
22+
/**
23+
* Resolves modules according to Node's resolution rules.
24+
*
25+
* @param {RequireResolve} resolve Node-like require.resolve implementation.
26+
* @param {string} id Module name or path.
27+
* @param {string[]} [paths] Additional paths to resolve from.
28+
* @returns {string} Resolved module path.
29+
*/
30+
const resolveModuleCustomResolve = (resolve, id, paths = []) => {
31+
// resolve.paths is sometimes not present under webpack or VS Code
32+
// @ts-ignore
33+
const resolvePaths = resolve.paths?.("") || [];
34+
const allPaths = [ ...paths, ...resolvePaths ];
35+
return resolve(id, { "paths": allPaths });
36+
};
37+
38+
/**
39+
* Resolves modules according to Node's resolution rules.
40+
*
41+
* @param {string} id Module name or path.
42+
* @param {string[]} [paths] Additional paths to resolve from.
43+
* @returns {string} Resolved module path.
44+
*/
45+
const resolveModule = (id, paths) => (
46+
resolveModuleCustomResolve(nativeRequire.resolve, id, paths)
47+
);
48+
49+
module.exports = {
50+
resolveModule,
51+
resolveModuleCustomResolve
52+
};

Diff for: lib/resolve-module.d.cts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export type RequireResolveOptions = {
2+
/**
3+
* Additional paths to resolve from.
4+
*/
5+
paths?: string[];
6+
};
7+
export type RequireResolve = (id: string, options: RequireResolveOptions) => string;
8+
/**
9+
* Resolves modules according to Node's resolution rules.
10+
*
11+
* @param {string} id Module name or path.
12+
* @param {string[]} [paths] Additional paths to resolve from.
13+
* @returns {string} Resolved module path.
14+
*/
15+
export function resolveModule(id: string, paths?: string[]): string;
16+
/**
17+
* @typedef RequireResolveOptions
18+
* @property {string[]} [paths] Additional paths to resolve from.
19+
*/
20+
/**
21+
* @callback RequireResolve
22+
* @param {string} id Module name or path.
23+
* @param {RequireResolveOptions} options Options to apply.
24+
* @returns {string} Resolved module path.
25+
*/
26+
/**
27+
* Resolves modules according to Node's resolution rules.
28+
*
29+
* @param {RequireResolve} resolve Node-like require.resolve implementation.
30+
* @param {string} id Module name or path.
31+
* @param {string[]} [paths] Additional paths to resolve from.
32+
* @returns {string} Resolved module path.
33+
*/
34+
export function resolveModuleCustomResolve(resolve: RequireResolve, id: string, paths?: string[]): string;

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"build-config": "npm run build-config-schema && npm run build-config-example",
3737
"build-config-example": "node schema/build-config-example.mjs",
3838
"build-config-schema": "node schema/build-config-schema.mjs",
39-
"build-declaration": "tsc --allowJs --checkJs --declaration --emitDeclarationOnly --module nodenext --outDir dts --rootDir . --target es2015 lib/exports.mjs lib/exports-async.mjs lib/exports-promise.mjs lib/exports-sync.mjs lib/markdownlint.mjs && node scripts/index.mjs copy dts/lib/exports.d.mts lib/exports.d.mts && node scripts/index.mjs copy dts/lib/exports-async.d.mts lib/exports-async.d.mts && node scripts/index.mjs copy dts/lib/exports-promise.d.mts lib/exports-promise.d.mts && node scripts/index.mjs copy dts/lib/exports-sync.d.mts lib/exports-sync.d.mts && node scripts/index.mjs copy dts/lib/markdownlint.d.mts lib/markdownlint.d.mts && node scripts/index.mjs remove dts",
39+
"build-declaration": "tsc --allowJs --checkJs --declaration --emitDeclarationOnly --module nodenext --outDir dts --rootDir . --target es2015 lib/exports.mjs lib/exports-async.mjs lib/exports-promise.mjs lib/exports-sync.mjs lib/markdownlint.mjs lib/resolve-module.cjs && node scripts/index.mjs copy dts/lib/exports.d.mts lib/exports.d.mts && node scripts/index.mjs copy dts/lib/exports-async.d.mts lib/exports-async.d.mts && node scripts/index.mjs copy dts/lib/exports-promise.d.mts lib/exports-promise.d.mts && node scripts/index.mjs copy dts/lib/exports-sync.d.mts lib/exports-sync.d.mts && node scripts/index.mjs copy dts/lib/markdownlint.d.mts lib/markdownlint.d.mts && node scripts/index.mjs copy dts/lib/resolve-module.d.cts lib/resolve-module.d.cts && node scripts/index.mjs remove dts",
4040
"build-demo": "node scripts/index.mjs copy node_modules/markdown-it/dist/markdown-it.min.js demo/markdown-it.min.js && cd demo && webpack --no-stats",
4141
"build-docs": "node doc-build/build-rules.mjs",
4242
"build-example": "npm install --no-save --ignore-scripts grunt grunt-cli gulp through2",
@@ -59,7 +59,7 @@
5959
"lint-test-repos": "ava --timeout=10m test/markdownlint-test-repos-*.mjs",
6060
"serial-config-docs": "npm run build-config && npm run build-docs",
6161
"serial-declaration-demo": "npm run build-declaration && npm-run-all --continue-on-error --parallel build-demo test-declaration",
62-
"test": "ava --timeout=30s test/markdownlint-test.mjs test/markdownlint-test-config.mjs test/markdownlint-test-custom-rules.mjs test/markdownlint-test-fixes.mjs test/markdownlint-test-helpers.mjs test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.mjs test/markdownlint-test-scenarios.mjs helpers/test.cjs",
62+
"test": "ava --timeout=30s test/markdownlint-test.mjs test/markdownlint-test-config.mjs test/markdownlint-test-custom-rules.mjs test/markdownlint-test-fixes.mjs test/markdownlint-test-helpers.mjs test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.mjs test/markdownlint-test-scenarios.mjs test/resolve-module-test.mjs helpers/test.cjs",
6363
"test-cover": "c8 --100 npm test",
6464
"test-declaration": "cd example/typescript && tsc --module commonjs && tsc --module nodenext && node type-check.js",
6565
"test-extra": "ava --timeout=10m test/markdownlint-test-extra-parse.mjs test/markdownlint-test-extra-type.mjs",

Diff for: test/resolve-module-test.mjs

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// @ts-check
2+
3+
import test from "ava";
4+
import path from "node:path";
5+
import { __dirname as getDirname } from "./esm-helpers.mjs";
6+
import { resolveModule, resolveModuleCustomResolve } from "../lib/resolve-module.cjs";
7+
8+
import { createRequire } from "node:module";
9+
const require = createRequire(import.meta.url);
10+
// eslint-disable-next-line no-underscore-dangle
11+
const __dirname = getDirname(import.meta);
12+
13+
test("built-in module", (t) => {
14+
t.plan(1);
15+
t.deepEqual(
16+
resolveModule("node:fs"),
17+
require.resolve("node:fs")
18+
);
19+
});
20+
21+
test("locally-installed module", (t) => {
22+
t.plan(1);
23+
t.deepEqual(
24+
resolveModule("micromark"),
25+
require.resolve("micromark")
26+
);
27+
});
28+
29+
test("absolute path to module", (t) => {
30+
t.plan(1);
31+
const absolute =
32+
path.resolve(
33+
__dirname,
34+
"./rules/node_modules/markdownlint-rule-sample-commonjs"
35+
);
36+
t.deepEqual(
37+
resolveModule(absolute),
38+
require.resolve(absolute)
39+
);
40+
});
41+
42+
test("relative (to __dirname) path to module", (t) => {
43+
t.plan(1);
44+
t.deepEqual(
45+
resolveModule(
46+
"./rules/node_modules/markdownlint-rule-sample-module",
47+
// __dirname is needed because require.resolve is relative to this
48+
// file while resolveModule is relative to resolve-module.cjs
49+
[ __dirname ]
50+
),
51+
require.resolve(
52+
"./rules/node_modules/markdownlint-rule-sample-module"
53+
)
54+
);
55+
});
56+
57+
test("module in alternate node_modules", (t) => {
58+
t.plan(3);
59+
t.throws(
60+
() => require.resolve("markdownlint-rule-sample-commonjs"),
61+
{ "code": "MODULE_NOT_FOUND" }
62+
);
63+
t.throws(
64+
() => resolveModule("markdownlint-rule-sample-commonjs"),
65+
{ "code": "MODULE_NOT_FOUND" }
66+
);
67+
t.deepEqual(
68+
resolveModule(
69+
"markdownlint-rule-sample-commonjs",
70+
[ path.join(__dirname, "rules") ]
71+
),
72+
require.resolve(
73+
"markdownlint-rule-sample-commonjs",
74+
{ "paths": [ path.join(__dirname, "rules") ] }
75+
)
76+
);
77+
});
78+
79+
test("module local, relative, and in alternate node_modules (same paths)", (t) => {
80+
t.plan(3);
81+
const paths = [
82+
__dirname,
83+
path.join(__dirname, "rules")
84+
];
85+
t.deepEqual(
86+
resolveModule(
87+
"micromark",
88+
paths
89+
),
90+
require.resolve(
91+
"micromark",
92+
{ paths }
93+
)
94+
);
95+
t.deepEqual(
96+
resolveModule(
97+
"./rules/node_modules/markdownlint-rule-sample-commonjs",
98+
paths
99+
),
100+
require.resolve(
101+
"./rules/node_modules/markdownlint-rule-sample-commonjs",
102+
{ paths }
103+
)
104+
);
105+
t.deepEqual(
106+
resolveModule(
107+
"markdownlint-rule-sample-commonjs",
108+
paths
109+
),
110+
require.resolve(
111+
"markdownlint-rule-sample-commonjs",
112+
{ paths }
113+
)
114+
);
115+
});
116+
117+
test("custom resolve implementation", (t) => {
118+
t.plan(1);
119+
const expected =
120+
require.resolve("./rules/node_modules/markdownlint-rule-sample-module");
121+
const customResolve = (id, options) => require.resolve(id, options);
122+
customResolve.paths = (request) => require.resolve.paths(request);
123+
t.deepEqual(
124+
resolveModuleCustomResolve(
125+
customResolve,
126+
"./rules/node_modules/markdownlint-rule-sample-module",
127+
[ __dirname ]
128+
),
129+
expected
130+
);
131+
});
132+
133+
test("custom resolve implementation, missing paths", (t) => {
134+
t.plan(1);
135+
const expected =
136+
require.resolve("./rules/node_modules/markdownlint-rule-sample-commonjs");
137+
const customResolve = (id, options) => require.resolve(id, options);
138+
t.deepEqual(
139+
resolveModuleCustomResolve(
140+
// @ts-ignore
141+
customResolve,
142+
"./rules/node_modules/markdownlint-rule-sample-commonjs",
143+
[ __dirname ]
144+
),
145+
expected
146+
);
147+
});

Diff for: test/rules/node_modules/markdownlint-rule-sample-commonjs/package.json

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)