feat(mdx-loader): upgrade to MDX v3 + (#9451)

This commit is contained in:
Sébastien Lorber 2023-10-26 15:47:11 +02:00 committed by GitHub
parent 8d19054d91
commit 7e456ece3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 37351 additions and 30469 deletions

20
jest.config.mjs vendored
View file

@ -86,16 +86,20 @@ export default {
// MDX packages are ESM-only and it is a pain to use in Jest // MDX packages are ESM-only and it is a pain to use in Jest
// So we use them in Jest tests as CJS versions // So we use them in Jest tests as CJS versions
// see https://mdxjs.com/docs/troubleshooting-mdx/#problems-integrating-mdx // see https://mdxjs.com/docs/troubleshooting-mdx/#problems-integrating-mdx
'^unified$': '<rootDir>/jest/vendor/unified@10.1.2.js', '^@mdx-js/mdx$': '<rootDir>/jest/vendor/@mdx-js__mdx@3.0.0.js',
'^@mdx-js/mdx$': '<rootDir>/jest/vendor/@mdx-js__mdx@2.1.5.js', '^remark$': '<rootDir>/jest/vendor/remark@15.0.1.js',
'^remark$': '<rootDir>/jest/vendor/remark@14.0.2.js', '^remark-rehype$': '<rootDir>/jest/vendor/remark-rehype@11.0.0.js',
'^remark-mdx$': '<rootDir>/jest/vendor/remark-mdx@2.1.5.js', '^remark-mdx$': '<rootDir>/jest/vendor/remark-mdx@3.0.0.js',
'^remark-directive$': '<rootDir>/jest/vendor/remark-directive@2.0.1.js', '^remark-directive$': '<rootDir>/jest/vendor/remark-directive@3.0.0.js',
'^remark-gfm$': '<rootDir>/jest/vendor/remark-gfm@3.0.1.js', '^remark-gfm$': '<rootDir>/jest/vendor/remark-gfm@4.0.0.js',
'^estree-util-value-to-estree$': '^estree-util-value-to-estree$':
'<rootDir>/jest/vendor/estree-util-value-to-estree@2.1.0.js', '<rootDir>/jest/vendor/estree-util-value-to-estree@3.0.1.js',
'^mdast-util-to-string$': '^mdast-util-to-string$':
'<rootDir>/jest/vendor/mdast-util-to-string@3.1.0.js', '<rootDir>/jest/vendor/mdast-util-to-string@4.0.0.js',
'^unist-util-visit$': '<rootDir>/jest/vendor/unist-util-visit@5.0.0.js',
'^unist-util-remove-position$':
'<rootDir>/jest/vendor/unist-util-remove-position@5.0.0.js',
'^rehype-stringify$': '<rootDir>/jest/vendor/rehype-stringify@10.0.0.js',
}, },
snapshotSerializers: [ snapshotSerializers: [
'<rootDir>/jest/snapshotPathNormalizer.ts', '<rootDir>/jest/snapshotPathNormalizer.ts',

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@ __export(estree_util_value_to_estree_exports, {
}); });
module.exports = __toCommonJS(estree_util_value_to_estree_exports); module.exports = __toCommonJS(estree_util_value_to_estree_exports);
// node_modules/estree-util-value-to-estree/node_modules/is-plain-obj/index.js // node_modules/is-plain-obj/index.js
function isPlainObject(value) { function isPlainObject(value) {
if (typeof value !== "object" || value === null) { if (typeof value !== "object" || value === null) {
return false; return false;
@ -49,7 +49,7 @@ function valueToEstree(value, options = {}) {
}; };
} }
if (typeof value === "number") { if (typeof value === "number") {
return value >= 0 ? { type: "Literal", value } : { return value >= 0 && !Object.is(value, -0) ? { type: "Literal", value } : {
type: "UnaryExpression", type: "UnaryExpression",
operator: "-", operator: "-",
prefix: true, prefix: true,
@ -130,9 +130,7 @@ function valueToEstree(value, options = {}) {
}; };
} }
if (options.instanceAsObject || isPlainObject(value)) { if (options.instanceAsObject || isPlainObject(value)) {
return { const properties = Reflect.ownKeys(value).map((key) => ({
type: "ObjectExpression",
properties: Reflect.ownKeys(value).map((key) => ({
type: "Property", type: "Property",
method: false, method: false,
shorthand: false, shorthand: false,
@ -140,7 +138,21 @@ function valueToEstree(value, options = {}) {
kind: "init", kind: "init",
key: valueToEstree(key, options), key: valueToEstree(key, options),
value: valueToEstree(value[key], options) value: valueToEstree(value[key], options)
})) }));
if (Object.getPrototypeOf(value) == null) {
properties.unshift({
type: "Property",
method: false,
shorthand: false,
computed: false,
kind: "init",
key: { type: "Identifier", name: "__proto__" },
value: { type: "Literal", value: null }
});
}
return {
type: "ObjectExpression",
properties
}; };
} }
throw new TypeError(`Unsupported value: ${String(value)}`); throw new TypeError(`Unsupported value: ${String(value)}`);

View file

@ -22,21 +22,43 @@ __export(mdast_util_to_string_exports, {
toString: () => toString toString: () => toString
}); });
module.exports = __toCommonJS(mdast_util_to_string_exports); module.exports = __toCommonJS(mdast_util_to_string_exports);
function toString(node, options) {
var { includeImageAlt = true } = options || {}; // node_modules/mdast-util-to-string/lib/index.js
return one(node, includeImageAlt); var emptyOptions = {};
function toString(value, options) {
const settings = options || emptyOptions;
const includeImageAlt = typeof settings.includeImageAlt === "boolean" ? settings.includeImageAlt : true;
const includeHtml = typeof settings.includeHtml === "boolean" ? settings.includeHtml : true;
return one(value, includeImageAlt, includeHtml);
} }
function one(node, includeImageAlt) { function one(value, includeImageAlt, includeHtml) {
return node && typeof node === "object" && (node.value || (includeImageAlt ? node.alt : "") || "children" in node && all(node.children, includeImageAlt) || Array.isArray(node) && all(node, includeImageAlt)) || ""; if (node(value)) {
if ("value" in value) {
return value.type === "html" && !includeHtml ? "" : value.value;
} }
function all(values, includeImageAlt) { if (includeImageAlt && "alt" in value && value.alt) {
var result = []; return value.alt;
var index = -1; }
if ("children" in value) {
return all(value.children, includeImageAlt, includeHtml);
}
}
if (Array.isArray(value)) {
return all(value, includeImageAlt, includeHtml);
}
return "";
}
function all(values, includeImageAlt, includeHtml) {
const result = [];
let index = -1;
while (++index < values.length) { while (++index < values.length) {
result[index] = one(values[index], includeImageAlt); result[index] = one(values[index], includeImageAlt, includeHtml);
} }
return result.join(""); return result.join("");
} }
function node(value) {
return Boolean(value && typeof value === "object");
}
// Annotate the CommonJS export names for ESM import in node: // Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = { 0 && (module.exports = {
toString toString

2202
jest/vendor/rehype-stringify@10.0.0.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

3457
jest/vendor/remark-gfm@4.0.0.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1334
jest/vendor/remark-rehype@11.0.0.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,779 +0,0 @@
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/is-buffer/index.js
var require_is_buffer = __commonJS({
"node_modules/is-buffer/index.js"(exports, module2) {
module2.exports = function isBuffer2(obj) {
return obj != null && obj.constructor != null && typeof obj.constructor.isBuffer === "function" && obj.constructor.isBuffer(obj);
};
}
});
// node_modules/extend/index.js
var require_extend = __commonJS({
"node_modules/extend/index.js"(exports, module2) {
"use strict";
var hasOwn = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;
var defineProperty = Object.defineProperty;
var gOPD = Object.getOwnPropertyDescriptor;
var isArray = function isArray2(arr) {
if (typeof Array.isArray === "function") {
return Array.isArray(arr);
}
return toStr.call(arr) === "[object Array]";
};
var isPlainObject2 = function isPlainObject3(obj) {
if (!obj || toStr.call(obj) !== "[object Object]") {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, "constructor");
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, "isPrototypeOf");
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) {
}
return typeof key === "undefined" || hasOwn.call(obj, key);
};
var setProperty = function setProperty2(target, options) {
if (defineProperty && options.name === "__proto__") {
defineProperty(target, options.name, {
enumerable: true,
configurable: true,
value: options.newValue,
writable: true
});
} else {
target[options.name] = options.newValue;
}
};
var getProperty = function getProperty2(obj, name) {
if (name === "__proto__") {
if (!hasOwn.call(obj, name)) {
return void 0;
} else if (gOPD) {
return gOPD(obj, name).value;
}
}
return obj[name];
};
module2.exports = function extend2() {
var options, name, src, copy, copyIsArray, clone;
var target = arguments[0];
var i = 1;
var length = arguments.length;
var deep = false;
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || typeof target !== "object" && typeof target !== "function") {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = getProperty(target, name);
copy = getProperty(options, name);
if (target !== copy) {
if (deep && copy && (isPlainObject2(copy) || (copyIsArray = isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && isArray(src) ? src : [];
} else {
clone = src && isPlainObject2(src) ? src : {};
}
setProperty(target, { name, newValue: extend2(deep, clone, copy) });
} else if (typeof copy !== "undefined") {
setProperty(target, { name, newValue: copy });
}
}
}
}
}
return target;
};
}
});
// node_modules/unified/index.js
var unified_exports = {};
__export(unified_exports, {
unified: () => unified1012
});
module.exports = __toCommonJS(unified_exports);
// node_modules/bail/index.js
function bail(error) {
if (error) {
throw error;
}
}
// node_modules/unified/lib/index.js
var import_is_buffer2 = __toESM(require_is_buffer(), 1);
var import_extend = __toESM(require_extend(), 1);
// node_modules/unified/node_modules/is-plain-obj/index.js
function isPlainObject(value) {
if (typeof value !== "object" || value === null) {
return false;
}
const prototype = Object.getPrototypeOf(value);
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
}
// node_modules/trough/index.js
function trough() {
const fns = [];
const pipeline = { run, use };
return pipeline;
function run(...values) {
let middlewareIndex = -1;
const callback = values.pop();
if (typeof callback !== "function") {
throw new TypeError("Expected function as last argument, not " + callback);
}
next(null, ...values);
function next(error, ...output) {
const fn = fns[++middlewareIndex];
let index2 = -1;
if (error) {
callback(error);
return;
}
while (++index2 < values.length) {
if (output[index2] === null || output[index2] === void 0) {
output[index2] = values[index2];
}
}
values = output;
if (fn) {
wrap(fn, next)(...output);
} else {
callback(null, ...output);
}
}
}
function use(middelware) {
if (typeof middelware !== "function") {
throw new TypeError(
"Expected `middelware` to be a function, not " + middelware
);
}
fns.push(middelware);
return pipeline;
}
}
function wrap(middleware, callback) {
let called;
return wrapped;
function wrapped(...parameters) {
const fnExpectsCallback = middleware.length > parameters.length;
let result;
if (fnExpectsCallback) {
parameters.push(done);
}
try {
result = middleware.apply(this, parameters);
} catch (error) {
const exception = error;
if (fnExpectsCallback && called) {
throw exception;
}
return done(exception);
}
if (!fnExpectsCallback) {
if (result instanceof Promise) {
result.then(then, done);
} else if (result instanceof Error) {
done(result);
} else {
then(result);
}
}
}
function done(error, ...output) {
if (!called) {
called = true;
callback(error, ...output);
}
}
function then(value) {
done(null, value);
}
}
// node_modules/vfile/lib/index.js
var import_is_buffer = __toESM(require_is_buffer(), 1);
// node_modules/unist-util-stringify-position/index.js
function stringifyPosition(value) {
if (!value || typeof value !== "object") {
return "";
}
if ("position" in value || "type" in value) {
return position(value.position);
}
if ("start" in value || "end" in value) {
return position(value);
}
if ("line" in value || "column" in value) {
return point(value);
}
return "";
}
function point(point2) {
return index(point2 && point2.line) + ":" + index(point2 && point2.column);
}
function position(pos) {
return point(pos && pos.start) + "-" + point(pos && pos.end);
}
function index(value) {
return value && typeof value === "number" ? value : 1;
}
// node_modules/vfile-message/index.js
var VFileMessage = class extends Error {
constructor(reason, place, origin) {
const parts = [null, null];
let position2 = {
start: { line: null, column: null },
end: { line: null, column: null }
};
super();
if (typeof place === "string") {
origin = place;
place = void 0;
}
if (typeof origin === "string") {
const index2 = origin.indexOf(":");
if (index2 === -1) {
parts[1] = origin;
} else {
parts[0] = origin.slice(0, index2);
parts[1] = origin.slice(index2 + 1);
}
}
if (place) {
if ("type" in place || "position" in place) {
if (place.position) {
position2 = place.position;
}
} else if ("start" in place || "end" in place) {
position2 = place;
} else if ("line" in place || "column" in place) {
position2.start = place;
}
}
this.name = stringifyPosition(place) || "1:1";
this.message = typeof reason === "object" ? reason.message : reason;
this.stack = "";
if (typeof reason === "object" && reason.stack) {
this.stack = reason.stack;
}
this.reason = this.message;
this.fatal;
this.line = position2.start.line;
this.column = position2.start.column;
this.position = position2;
this.source = parts[0];
this.ruleId = parts[1];
this.file;
this.actual;
this.expected;
this.url;
this.note;
}
};
VFileMessage.prototype.file = "";
VFileMessage.prototype.name = "";
VFileMessage.prototype.reason = "";
VFileMessage.prototype.message = "";
VFileMessage.prototype.stack = "";
VFileMessage.prototype.fatal = null;
VFileMessage.prototype.column = null;
VFileMessage.prototype.line = null;
VFileMessage.prototype.source = null;
VFileMessage.prototype.ruleId = null;
VFileMessage.prototype.position = null;
// node_modules/vfile/lib/minpath.js
var import_path = __toESM(require("path"), 1);
// node_modules/vfile/lib/minproc.js
var import_process = __toESM(require("process"), 1);
// node_modules/vfile/lib/minurl.js
var import_url = require("url");
// node_modules/vfile/lib/minurl.shared.js
function isUrl(fileURLOrPath) {
return fileURLOrPath !== null && typeof fileURLOrPath === "object" && fileURLOrPath.href && fileURLOrPath.origin;
}
// node_modules/vfile/lib/index.js
var order = ["history", "path", "basename", "stem", "extname", "dirname"];
var VFile = class {
constructor(value) {
let options;
if (!value) {
options = {};
} else if (typeof value === "string" || (0, import_is_buffer.default)(value)) {
options = { value };
} else if (isUrl(value)) {
options = { path: value };
} else {
options = value;
}
this.data = {};
this.messages = [];
this.history = [];
this.cwd = import_process.default.cwd();
this.value;
this.stored;
this.result;
this.map;
let index2 = -1;
while (++index2 < order.length) {
const prop2 = order[index2];
if (prop2 in options && options[prop2] !== void 0) {
this[prop2] = prop2 === "history" ? [...options[prop2]] : options[prop2];
}
}
let prop;
for (prop in options) {
if (!order.includes(prop))
this[prop] = options[prop];
}
}
get path() {
return this.history[this.history.length - 1];
}
set path(path) {
if (isUrl(path)) {
path = (0, import_url.fileURLToPath)(path);
}
assertNonEmpty(path, "path");
if (this.path !== path) {
this.history.push(path);
}
}
get dirname() {
return typeof this.path === "string" ? import_path.default.dirname(this.path) : void 0;
}
set dirname(dirname) {
assertPath(this.basename, "dirname");
this.path = import_path.default.join(dirname || "", this.basename);
}
get basename() {
return typeof this.path === "string" ? import_path.default.basename(this.path) : void 0;
}
set basename(basename) {
assertNonEmpty(basename, "basename");
assertPart(basename, "basename");
this.path = import_path.default.join(this.dirname || "", basename);
}
get extname() {
return typeof this.path === "string" ? import_path.default.extname(this.path) : void 0;
}
set extname(extname) {
assertPart(extname, "extname");
assertPath(this.dirname, "extname");
if (extname) {
if (extname.charCodeAt(0) !== 46) {
throw new Error("`extname` must start with `.`");
}
if (extname.includes(".", 1)) {
throw new Error("`extname` cannot contain multiple dots");
}
}
this.path = import_path.default.join(this.dirname, this.stem + (extname || ""));
}
get stem() {
return typeof this.path === "string" ? import_path.default.basename(this.path, this.extname) : void 0;
}
set stem(stem) {
assertNonEmpty(stem, "stem");
assertPart(stem, "stem");
this.path = import_path.default.join(this.dirname || "", stem + (this.extname || ""));
}
toString(encoding) {
return (this.value || "").toString(encoding);
}
message(reason, place, origin) {
const message = new VFileMessage(reason, place, origin);
if (this.path) {
message.name = this.path + ":" + message.name;
message.file = this.path;
}
message.fatal = false;
this.messages.push(message);
return message;
}
info(reason, place, origin) {
const message = this.message(reason, place, origin);
message.fatal = null;
return message;
}
fail(reason, place, origin) {
const message = this.message(reason, place, origin);
message.fatal = true;
throw message;
}
};
function assertPart(part, name) {
if (part && part.includes(import_path.default.sep)) {
throw new Error(
"`" + name + "` cannot be a path: did not expect `" + import_path.default.sep + "`"
);
}
}
function assertNonEmpty(part, name) {
if (!part) {
throw new Error("`" + name + "` cannot be empty");
}
}
function assertPath(path, name) {
if (!path) {
throw new Error("Setting `" + name + "` requires `path` to be set too");
}
}
// node_modules/unified/lib/index.js
var unified1012 = base().freeze();
var own = {}.hasOwnProperty;
function base() {
const transformers = trough();
const attachers = [];
let namespace = {};
let frozen;
let freezeIndex = -1;
processor.data = data;
processor.Parser = void 0;
processor.Compiler = void 0;
processor.freeze = freeze;
processor.attachers = attachers;
processor.use = use;
processor.parse = parse;
processor.stringify = stringify;
processor.run = run;
processor.runSync = runSync;
processor.process = process;
processor.processSync = processSync;
return processor;
function processor() {
const destination = base();
let index2 = -1;
while (++index2 < attachers.length) {
destination.use(...attachers[index2]);
}
destination.data((0, import_extend.default)(true, {}, namespace));
return destination;
}
function data(key, value) {
if (typeof key === "string") {
if (arguments.length === 2) {
assertUnfrozen("data", frozen);
namespace[key] = value;
return processor;
}
return own.call(namespace, key) && namespace[key] || null;
}
if (key) {
assertUnfrozen("data", frozen);
namespace = key;
return processor;
}
return namespace;
}
function freeze() {
if (frozen) {
return processor;
}
while (++freezeIndex < attachers.length) {
const [attacher, ...options] = attachers[freezeIndex];
if (options[0] === false) {
continue;
}
if (options[0] === true) {
options[0] = void 0;
}
const transformer = attacher.call(processor, ...options);
if (typeof transformer === "function") {
transformers.use(transformer);
}
}
frozen = true;
freezeIndex = Number.POSITIVE_INFINITY;
return processor;
}
function use(value, ...options) {
let settings;
assertUnfrozen("use", frozen);
if (value === null || value === void 0) {
} else if (typeof value === "function") {
addPlugin(value, ...options);
} else if (typeof value === "object") {
if (Array.isArray(value)) {
addList(value);
} else {
addPreset(value);
}
} else {
throw new TypeError("Expected usable value, not `" + value + "`");
}
if (settings) {
namespace.settings = Object.assign(namespace.settings || {}, settings);
}
return processor;
function add(value2) {
if (typeof value2 === "function") {
addPlugin(value2);
} else if (typeof value2 === "object") {
if (Array.isArray(value2)) {
const [plugin, ...options2] = value2;
addPlugin(plugin, ...options2);
} else {
addPreset(value2);
}
} else {
throw new TypeError("Expected usable value, not `" + value2 + "`");
}
}
function addPreset(result) {
addList(result.plugins);
if (result.settings) {
settings = Object.assign(settings || {}, result.settings);
}
}
function addList(plugins) {
let index2 = -1;
if (plugins === null || plugins === void 0) {
} else if (Array.isArray(plugins)) {
while (++index2 < plugins.length) {
const thing = plugins[index2];
add(thing);
}
} else {
throw new TypeError("Expected a list of plugins, not `" + plugins + "`");
}
}
function addPlugin(plugin, value2) {
let index2 = -1;
let entry;
while (++index2 < attachers.length) {
if (attachers[index2][0] === plugin) {
entry = attachers[index2];
break;
}
}
if (entry) {
if (isPlainObject(entry[1]) && isPlainObject(value2)) {
value2 = (0, import_extend.default)(true, entry[1], value2);
}
entry[1] = value2;
} else {
attachers.push([...arguments]);
}
}
}
function parse(doc) {
processor.freeze();
const file = vfile(doc);
const Parser = processor.Parser;
assertParser("parse", Parser);
if (newable(Parser, "parse")) {
return new Parser(String(file), file).parse();
}
return Parser(String(file), file);
}
function stringify(node, doc) {
processor.freeze();
const file = vfile(doc);
const Compiler = processor.Compiler;
assertCompiler("stringify", Compiler);
assertNode(node);
if (newable(Compiler, "compile")) {
return new Compiler(node, file).compile();
}
return Compiler(node, file);
}
function run(node, doc, callback) {
assertNode(node);
processor.freeze();
if (!callback && typeof doc === "function") {
callback = doc;
doc = void 0;
}
if (!callback) {
return new Promise(executor);
}
executor(null, callback);
function executor(resolve, reject) {
transformers.run(node, vfile(doc), done);
function done(error, tree, file) {
tree = tree || node;
if (error) {
reject(error);
} else if (resolve) {
resolve(tree);
} else {
callback(null, tree, file);
}
}
}
}
function runSync(node, file) {
let result;
let complete;
processor.run(node, file, done);
assertDone("runSync", "run", complete);
return result;
function done(error, tree) {
bail(error);
result = tree;
complete = true;
}
}
function process(doc, callback) {
processor.freeze();
assertParser("process", processor.Parser);
assertCompiler("process", processor.Compiler);
if (!callback) {
return new Promise(executor);
}
executor(null, callback);
function executor(resolve, reject) {
const file = vfile(doc);
processor.run(processor.parse(file), file, (error, tree, file2) => {
if (error || !tree || !file2) {
done(error);
} else {
const result = processor.stringify(tree, file2);
if (result === void 0 || result === null) {
} else if (looksLikeAVFileValue(result)) {
file2.value = result;
} else {
file2.result = result;
}
done(error, file2);
}
});
function done(error, file2) {
if (error || !file2) {
reject(error);
} else if (resolve) {
resolve(file2);
} else {
callback(null, file2);
}
}
}
}
function processSync(doc) {
let complete;
processor.freeze();
assertParser("processSync", processor.Parser);
assertCompiler("processSync", processor.Compiler);
const file = vfile(doc);
processor.process(file, done);
assertDone("processSync", "process", complete);
return file;
function done(error) {
complete = true;
bail(error);
}
}
}
function newable(value, name) {
return typeof value === "function" && value.prototype && (keys(value.prototype) || name in value.prototype);
}
function keys(value) {
let key;
for (key in value) {
if (own.call(value, key)) {
return true;
}
}
return false;
}
function assertParser(name, value) {
if (typeof value !== "function") {
throw new TypeError("Cannot `" + name + "` without `Parser`");
}
}
function assertCompiler(name, value) {
if (typeof value !== "function") {
throw new TypeError("Cannot `" + name + "` without `Compiler`");
}
}
function assertUnfrozen(name, frozen) {
if (frozen) {
throw new Error(
"Cannot call `" + name + "` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`."
);
}
}
function assertNode(node) {
if (!isPlainObject(node) || typeof node.type !== "string") {
throw new TypeError("Expected node, got `" + node + "`");
}
}
function assertDone(name, asyncName, complete) {
if (!complete) {
throw new Error(
"`" + name + "` finished async. Use `" + asyncName + "` instead"
);
}
}
function vfile(value) {
return looksLikeAVFile(value) ? value : new VFile(value);
}
function looksLikeAVFile(value) {
return Boolean(
value && typeof value === "object" && "message" in value && "messages" in value
);
}
function looksLikeAVFileValue(value) {
return typeof value === "string" || (0, import_is_buffer2.default)(value);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
unified: unified1012
});
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/

View file

@ -0,0 +1,240 @@
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/unist-util-remove-position/index.js
var unist_util_remove_position_exports = {};
__export(unist_util_remove_position_exports, {
removePosition: () => removePosition
});
module.exports = __toCommonJS(unist_util_remove_position_exports);
// node_modules/unist-util-is/lib/index.js
var convert = (
// Note: overloads in JSDoc cant yet use different `@template`s.
/**
* @type {(
* (<Condition extends string>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition}) &
* (<Condition extends Props>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Condition) &
* (<Condition extends TestFunction>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Predicate<Condition, Node>) &
* ((test?: null | undefined) => (node?: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node) &
* ((test?: Test) => Check)
* )}
*/
/**
* @param {Test} [test]
* @returns {Check}
*/
function(test) {
if (test === null || test === void 0) {
return ok;
}
if (typeof test === "function") {
return castFactory(test);
}
if (typeof test === "object") {
return Array.isArray(test) ? anyFactory(test) : propsFactory(test);
}
if (typeof test === "string") {
return typeFactory(test);
}
throw new Error("Expected function, string, or object as test");
}
);
function anyFactory(tests) {
const checks = [];
let index = -1;
while (++index < tests.length) {
checks[index] = convert(tests[index]);
}
return castFactory(any);
function any(...parameters) {
let index2 = -1;
while (++index2 < checks.length) {
if (checks[index2].apply(this, parameters))
return true;
}
return false;
}
}
function propsFactory(check) {
const checkAsRecord = (
/** @type {Record<string, unknown>} */
check
);
return castFactory(all);
function all(node) {
const nodeAsRecord = (
/** @type {Record<string, unknown>} */
/** @type {unknown} */
node
);
let key;
for (key in check) {
if (nodeAsRecord[key] !== checkAsRecord[key])
return false;
}
return true;
}
}
function typeFactory(check) {
return castFactory(type);
function type(node) {
return node && node.type === check;
}
}
function castFactory(testFunction) {
return check;
function check(value, index, parent) {
return Boolean(
looksLikeANode(value) && testFunction.call(
this,
value,
typeof index === "number" ? index : void 0,
parent || void 0
)
);
}
}
function ok() {
return true;
}
function looksLikeANode(value) {
return value !== null && typeof value === "object" && "type" in value;
}
// node_modules/unist-util-visit-parents/lib/color.node.js
function color(d) {
return "\x1B[33m" + d + "\x1B[39m";
}
// node_modules/unist-util-visit-parents/lib/index.js
var empty = [];
var CONTINUE = true;
var EXIT = false;
var SKIP = "skip";
function visitParents(tree, test, visitor, reverse) {
let check;
if (typeof test === "function" && typeof visitor !== "function") {
reverse = visitor;
visitor = test;
} else {
check = test;
}
const is2 = convert(check);
const step = reverse ? -1 : 1;
factory(tree, void 0, [])();
function factory(node, index, parents) {
const value = (
/** @type {Record<string, unknown>} */
node && typeof node === "object" ? node : {}
);
if (typeof value.type === "string") {
const name = (
// `hast`
typeof value.tagName === "string" ? value.tagName : (
// `xast`
typeof value.name === "string" ? value.name : void 0
)
);
Object.defineProperty(visit2, "name", {
value: "node (" + color(node.type + (name ? "<" + name + ">" : "")) + ")"
});
}
return visit2;
function visit2() {
let result = empty;
let subresult;
let offset;
let grandparents;
if (!test || is2(node, index, parents[parents.length - 1] || void 0)) {
result = toResult(visitor(node, parents));
if (result[0] === EXIT) {
return result;
}
}
if ("children" in node && node.children) {
const nodeAsParent = (
/** @type {UnistParent} */
node
);
if (nodeAsParent.children && result[0] !== SKIP) {
offset = (reverse ? nodeAsParent.children.length : -1) + step;
grandparents = parents.concat(nodeAsParent);
while (offset > -1 && offset < nodeAsParent.children.length) {
const child = nodeAsParent.children[offset];
subresult = factory(child, offset, grandparents)();
if (subresult[0] === EXIT) {
return subresult;
}
offset = typeof subresult[1] === "number" ? subresult[1] : offset + step;
}
}
}
return result;
}
}
}
function toResult(value) {
if (Array.isArray(value)) {
return value;
}
if (typeof value === "number") {
return [CONTINUE, value];
}
return value === null || value === void 0 ? empty : [value];
}
// node_modules/unist-util-visit/lib/index.js
function visit(tree, testOrVisitor, visitorOrReverse, maybeReverse) {
let reverse;
let test;
let visitor;
if (typeof testOrVisitor === "function" && typeof visitorOrReverse !== "function") {
test = void 0;
visitor = testOrVisitor;
reverse = visitorOrReverse;
} else {
test = testOrVisitor;
visitor = visitorOrReverse;
reverse = maybeReverse;
}
visitParents(tree, test, overload, reverse);
function overload(node, parents) {
const parent = parents[parents.length - 1];
const index = parent ? parent.children.indexOf(node) : void 0;
return visitor(node, index, parent);
}
}
// node_modules/unist-util-remove-position/lib/index.js
function removePosition(tree, options) {
const config = options || {};
const force = config.force || false;
visit(tree, remove);
function remove(node) {
if (force) {
delete node.position;
} else {
node.position = void 0;
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
removePosition
});

232
jest/vendor/unist-util-visit@5.0.0.js vendored Normal file
View file

@ -0,0 +1,232 @@
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/unist-util-visit/index.js
var unist_util_visit_exports = {};
__export(unist_util_visit_exports, {
CONTINUE: () => CONTINUE,
EXIT: () => EXIT,
SKIP: () => SKIP,
visit: () => visit
});
module.exports = __toCommonJS(unist_util_visit_exports);
// node_modules/unist-util-is/lib/index.js
var convert = (
// Note: overloads in JSDoc cant yet use different `@template`s.
/**
* @type {(
* (<Condition extends string>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & {type: Condition}) &
* (<Condition extends Props>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Condition) &
* (<Condition extends TestFunction>(test: Condition) => (node: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node & Predicate<Condition, Node>) &
* ((test?: null | undefined) => (node?: unknown, index?: number | null | undefined, parent?: Parent | null | undefined, context?: unknown) => node is Node) &
* ((test?: Test) => Check)
* )}
*/
/**
* @param {Test} [test]
* @returns {Check}
*/
function(test) {
if (test === null || test === void 0) {
return ok;
}
if (typeof test === "function") {
return castFactory(test);
}
if (typeof test === "object") {
return Array.isArray(test) ? anyFactory(test) : propsFactory(test);
}
if (typeof test === "string") {
return typeFactory(test);
}
throw new Error("Expected function, string, or object as test");
}
);
function anyFactory(tests) {
const checks = [];
let index = -1;
while (++index < tests.length) {
checks[index] = convert(tests[index]);
}
return castFactory(any);
function any(...parameters) {
let index2 = -1;
while (++index2 < checks.length) {
if (checks[index2].apply(this, parameters))
return true;
}
return false;
}
}
function propsFactory(check) {
const checkAsRecord = (
/** @type {Record<string, unknown>} */
check
);
return castFactory(all);
function all(node) {
const nodeAsRecord = (
/** @type {Record<string, unknown>} */
/** @type {unknown} */
node
);
let key;
for (key in check) {
if (nodeAsRecord[key] !== checkAsRecord[key])
return false;
}
return true;
}
}
function typeFactory(check) {
return castFactory(type);
function type(node) {
return node && node.type === check;
}
}
function castFactory(testFunction) {
return check;
function check(value, index, parent) {
return Boolean(
looksLikeANode(value) && testFunction.call(
this,
value,
typeof index === "number" ? index : void 0,
parent || void 0
)
);
}
}
function ok() {
return true;
}
function looksLikeANode(value) {
return value !== null && typeof value === "object" && "type" in value;
}
// node_modules/unist-util-visit-parents/lib/color.node.js
function color(d) {
return "\x1B[33m" + d + "\x1B[39m";
}
// node_modules/unist-util-visit-parents/lib/index.js
var empty = [];
var CONTINUE = true;
var EXIT = false;
var SKIP = "skip";
function visitParents(tree, test, visitor, reverse) {
let check;
if (typeof test === "function" && typeof visitor !== "function") {
reverse = visitor;
visitor = test;
} else {
check = test;
}
const is2 = convert(check);
const step = reverse ? -1 : 1;
factory(tree, void 0, [])();
function factory(node, index, parents) {
const value = (
/** @type {Record<string, unknown>} */
node && typeof node === "object" ? node : {}
);
if (typeof value.type === "string") {
const name = (
// `hast`
typeof value.tagName === "string" ? value.tagName : (
// `xast`
typeof value.name === "string" ? value.name : void 0
)
);
Object.defineProperty(visit2, "name", {
value: "node (" + color(node.type + (name ? "<" + name + ">" : "")) + ")"
});
}
return visit2;
function visit2() {
let result = empty;
let subresult;
let offset;
let grandparents;
if (!test || is2(node, index, parents[parents.length - 1] || void 0)) {
result = toResult(visitor(node, parents));
if (result[0] === EXIT) {
return result;
}
}
if ("children" in node && node.children) {
const nodeAsParent = (
/** @type {UnistParent} */
node
);
if (nodeAsParent.children && result[0] !== SKIP) {
offset = (reverse ? nodeAsParent.children.length : -1) + step;
grandparents = parents.concat(nodeAsParent);
while (offset > -1 && offset < nodeAsParent.children.length) {
const child = nodeAsParent.children[offset];
subresult = factory(child, offset, grandparents)();
if (subresult[0] === EXIT) {
return subresult;
}
offset = typeof subresult[1] === "number" ? subresult[1] : offset + step;
}
}
}
return result;
}
}
}
function toResult(value) {
if (Array.isArray(value)) {
return value;
}
if (typeof value === "number") {
return [CONTINUE, value];
}
return value === null || value === void 0 ? empty : [value];
}
// node_modules/unist-util-visit/lib/index.js
function visit(tree, testOrVisitor, visitorOrReverse, maybeReverse) {
let reverse;
let test;
let visitor;
if (typeof testOrVisitor === "function" && typeof visitorOrReverse !== "function") {
test = void 0;
visitor = testOrVisitor;
reverse = visitorOrReverse;
} else {
test = testOrVisitor;
visitor = visitorOrReverse;
reverse = maybeReverse;
}
visitParents(tree, test, overload, reverse);
function overload(node, parents) {
const parent = parents[parents.length - 1];
const index = parent ? parent.children.indexOf(node) : void 0;
return visitor(node, index, parent);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CONTINUE,
EXIT,
SKIP,
visit
});

View file

@ -62,9 +62,6 @@
"lock:update": "npx --yes yarn-deduplicate", "lock:update": "npx --yes yarn-deduplicate",
"update-translations": "yarn workspace @docusaurus/theme-translations update" "update-translations": "yarn workspace @docusaurus/theme-translations update"
}, },
"dependencies": {
"unified": "^10.1.2"
},
"devDependencies": { "devDependencies": {
"@crowdin/cli": "^3.13.0", "@crowdin/cli": "^3.13.0",
"@swc/core": "1.2.197", "@swc/core": "1.2.197",
@ -109,7 +106,6 @@
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
"react-helmet-async": "^1.3.0", "react-helmet-async": "^1.3.0",
"react-test-renderer": "^18.0.0", "react-test-renderer": "^18.0.0",
"remark-parse": "^8.0.3",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"sharp": "^0.32.3", "sharp": "^0.32.3",
"strip-ansi": "^6.0.1", "strip-ansi": "^6.0.1",

View file

@ -17,7 +17,7 @@
"dependencies": { "dependencies": {
"@docusaurus/core": "3.0.0-rc.0", "@docusaurus/core": "3.0.0-rc.0",
"@docusaurus/preset-classic": "3.0.0-rc.0", "@docusaurus/preset-classic": "3.0.0-rc.0",
"@mdx-js/react": "^2.3.0", "@mdx-js/react": "^3.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"prism-react-renderer": "^2.1.0", "prism-react-renderer": "^2.1.0",
"react": "^18.0.0", "react": "^18.0.0",

View file

@ -16,7 +16,7 @@
"dependencies": { "dependencies": {
"@docusaurus/core": "3.0.0-rc.0", "@docusaurus/core": "3.0.0-rc.0",
"@docusaurus/preset-classic": "3.0.0-rc.0", "@docusaurus/preset-classic": "3.0.0-rc.0",
"@mdx-js/react": "^2.3.0", "@mdx-js/react": "^3.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"prism-react-renderer": "^2.1.0", "prism-react-renderer": "^2.1.0",
"react": "^18.0.0", "react": "^18.0.0",

View file

@ -23,42 +23,41 @@
"@docusaurus/logger": "3.0.0-rc.0", "@docusaurus/logger": "3.0.0-rc.0",
"@docusaurus/utils": "3.0.0-rc.0", "@docusaurus/utils": "3.0.0-rc.0",
"@docusaurus/utils-validation": "3.0.0-rc.0", "@docusaurus/utils-validation": "3.0.0-rc.0",
"@mdx-js/mdx": "^2.1.5", "@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0", "@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"estree-util-value-to-estree": "^2.1.0", "estree-util-value-to-estree": "^3.0.1",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"hastscript": "^7.1.0",
"image-size": "^1.0.2", "image-size": "^1.0.2",
"mdast-util-mdx": "^2.0.0", "mdast-util-mdx": "^3.0.0",
"mdast-util-to-string": "^3.2.0", "mdast-util-to-string": "^4.0.0",
"rehype-raw": "^6.1.1", "rehype-raw": "^7.0.0",
"remark-directive": "^2.0.1", "remark-directive": "^3.0.0",
"remark-emoji": "^2.2.0", "remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0", "remark-frontmatter": "^5.0.0",
"remark-gfm": "^3.0.1", "remark-gfm": "^4.0.0",
"stringify-object": "^3.3.0", "stringify-object": "^3.3.0",
"tslib": "^2.6.0", "tslib": "^2.6.0",
"unified": "^10.1.2", "unified": "^11.0.3",
"unist-util-visit": "^2.0.3", "unist-util-visit": "^5.0.0",
"url-loader": "^4.1.1", "url-loader": "^4.1.1",
"vfile": "^5.3.7", "vfile": "^6.0.1",
"webpack": "^5.88.1" "webpack": "^5.88.1"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/types": "3.0.0-rc.0", "@docusaurus/types": "3.0.0-rc.0",
"@types/escape-html": "^1.0.2", "@types/escape-html": "^1.0.2",
"@types/mdast": "^3.0.12", "@types/mdast": "^4.0.2",
"@types/stringify-object": "^3.3.1", "@types/stringify-object": "^3.3.1",
"@types/unist": "^2.0.7", "@types/unist": "^3.0.1",
"rehype-stringify": "^8.0.0", "rehype-stringify": "^10.0.0",
"remark": "^14.0.3", "remark": "^15.0.1",
"remark-mdx": "^2.1.5", "remark-mdx": "^3.0.0",
"remark-rehype": "^8.1.0", "remark-rehype": "^11.0.0",
"to-vfile": "^6.1.0", "to-vfile": "^6.1.0",
"unist-builder": "^2.0.3", "unist-builder": "^2.0.3",
"unist-util-remove-position": "^3.0.0" "unist-util-remove-position": "^5.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^18.0.0", "react": "^18.0.0",

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import emoji from 'remark-emoji';
import headings from './remark/headings'; import headings from './remark/headings';
import contentTitle from './remark/contentTitle'; import contentTitle from './remark/contentTitle';
import toc from './remark/toc'; import toc from './remark/toc';
@ -48,13 +47,10 @@ type SimpleProcessor = {
}) => Promise<SimpleProcessorResult>; }) => Promise<SimpleProcessorResult>;
}; };
const DEFAULT_OPTIONS: MDXOptions = { async function getDefaultRemarkPlugins(): Promise<MDXPlugin[]> {
admonitions: true, const {default: emoji} = await import('remark-emoji');
rehypePlugins: [], return [headings, emoji, toc];
remarkPlugins: [headings, emoji, toc], }
beforeDefaultRemarkPlugins: [],
beforeDefaultRehypePlugins: [],
};
export type MDXPlugin = Pluggable; export type MDXPlugin = Pluggable;
@ -91,6 +87,8 @@ async function createProcessorFactory() {
const {default: directive} = await import('remark-directive'); const {default: directive} = await import('remark-directive');
const {VFile} = await import('vfile'); const {VFile} = await import('vfile');
const defaultRemarkPlugins = await getDefaultRemarkPlugins();
// /!\ this method is synchronous on purpose // /!\ this method is synchronous on purpose
// Using async code here can create cache entry race conditions! // Using async code here can create cache entry race conditions!
function createProcessorSync({ function createProcessorSync({
@ -106,7 +104,7 @@ async function createProcessorFactory() {
directive, directive,
[contentTitle, {removeContentTitle: options.removeContentTitle}], [contentTitle, {removeContentTitle: options.removeContentTitle}],
...getAdmonitionsPlugins(options.admonitions ?? false), ...getAdmonitionsPlugins(options.admonitions ?? false),
...DEFAULT_OPTIONS.remarkPlugins, ...defaultRemarkPlugins,
details, details,
head, head,
...(options.markdownConfig.mermaid ? [mermaid] : []), ...(options.markdownConfig.mermaid ? [mermaid] : []),
@ -136,7 +134,6 @@ async function createProcessorFactory() {
const rehypePlugins: MDXPlugin[] = [ const rehypePlugins: MDXPlugin[] = [
...(options.beforeDefaultRehypePlugins ?? []), ...(options.beforeDefaultRehypePlugins ?? []),
...DEFAULT_OPTIONS.rehypePlugins,
...(options.rehypePlugins ?? []), ...(options.rehypePlugins ?? []),
]; ];

View file

@ -4,7 +4,6 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer, Processor} from 'unified'; import type {Transformer, Processor} from 'unified';
@ -67,6 +66,7 @@ function parseDirective(directive: ContainerDirective): {
contentNodes: DirectiveContent; contentNodes: DirectiveContent;
} { } {
const hasDirectiveLabel = const hasDirectiveLabel =
// @ts-expect-error: fine
directive.children?.[0]?.data?.directiveLabel === true; directive.children?.[0]?.data?.directiveLabel === true;
if (hasDirectiveLabel) { if (hasDirectiveLabel) {
const [directiveLabel, ...contentNodes] = directive.children; const [directiveLabel, ...contentNodes] = directive.children;
@ -92,6 +92,8 @@ const plugin: Plugin = function plugin(
const {keywords} = normalizeAdmonitionOptions(optionsInput); const {keywords} = normalizeAdmonitionOptions(optionsInput);
return async (root) => { return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, (node) => { visit(root, (node) => {
if (node.type === 'containerDirective') { if (node.type === 'containerDirective') {
const directive = node as ContainerDirective; const directive = node as ContainerDirective;

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit, {EXIT} from 'unist-util-visit';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified'; import type {Transformer} from 'unified';
import type {Heading} from 'mdast'; import type {Heading} from 'mdast';
@ -33,11 +32,13 @@ const plugin: Plugin = function plugin(
return async (root, vfile) => { return async (root, vfile) => {
const {toString} = await import('mdast-util-to-string'); const {toString} = await import('mdast-util-to-string');
const {visit, EXIT} = await import('unist-util-visit');
visit(root, 'heading', (headingNode: Heading, index, parent) => { visit(root, 'heading', (headingNode: Heading, index, parent) => {
if (headingNode.depth === 1) { if (headingNode.depth === 1) {
vfile.data.compilerName;
vfile.data.contentTitle = toString(headingNode); vfile.data.contentTitle = toString(headingNode);
if (removeContentTitle) { if (removeContentTitle) {
// @ts-expect-error: TODO how to fix?
parent!.children.splice(index, 1); parent!.children.splice(index, 1);
} }
return EXIT; // We only handle the very first heading return EXIT; // We only handle the very first heading

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified'; import type {Transformer} from 'unified';
@ -15,7 +14,8 @@ import type {MdxJsxFlowElement} from 'mdast-util-mdx';
// Transform <details> to <Details> // Transform <details> to <Details>
// MDX 2 doesn't allow to substitute html elements with the provider anymore // MDX 2 doesn't allow to substitute html elements with the provider anymore
export default function plugin(): Transformer { export default function plugin(): Transformer {
return (root) => { return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => { visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => {
if (node.name === 'details') { if (node.name === 'details') {
node.name = 'Details'; node.name = 'Details';

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified'; import type {Transformer} from 'unified';
@ -15,7 +14,8 @@ import type {MdxJsxFlowElement} from 'mdast-util-mdx';
// Transform <head> to <Head> // Transform <head> to <Head>
// MDX 2 doesn't allow to substitute html elements with the provider anymore // MDX 2 doesn't allow to substitute html elements with the provider anymore
export default function plugin(): Transformer { export default function plugin(): Transformer {
return (root) => { return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => { visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => {
if (node.name === 'head') { if (node.name === 'head') {
node.name = 'Head'; node.name = 'Head';

View file

@ -8,9 +8,9 @@
/* Based on remark-slug (https://github.com/remarkjs/remark-slug) and gatsby-remark-autolink-headers (https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-remark-autolink-headers) */ /* Based on remark-slug (https://github.com/remarkjs/remark-slug) and gatsby-remark-autolink-headers (https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-remark-autolink-headers) */
import u from 'unist-builder'; import u from 'unist-builder';
import removePosition from 'unist-util-remove-position'; import {removePosition} from 'unist-util-remove-position';
import {toString} from 'mdast-util-to-string'; import {toString} from 'mdast-util-to-string';
import visit from 'unist-util-visit'; import {visit} from 'unist-util-visit';
import slug from '../index'; import slug from '../index';
import type {Plugin} from 'unified'; import type {Plugin} from 'unified';
import type {Parent} from 'unist'; import type {Parent} from 'unist';
@ -18,7 +18,9 @@ import type {Parent} from 'unist';
async function process(doc: string, plugins: Plugin[] = []) { async function process(doc: string, plugins: Plugin[] = []) {
const {remark} = await import('remark'); const {remark} = await import('remark');
const processor = await remark().use({plugins: [...plugins, slug]}); const processor = await remark().use({plugins: [...plugins, slug]});
return removePosition(await processor.run(processor.parse(doc)), true); const result = await processor.run(processor.parse(doc));
removePosition(result, {force: true});
return result;
} }
function heading(label: string | null, id: string) { function heading(label: string | null, id: string) {

View file

@ -8,7 +8,6 @@
/* Based on remark-slug (https://github.com/remarkjs/remark-slug) and gatsby-remark-autolink-headers (https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-remark-autolink-headers) */ /* Based on remark-slug (https://github.com/remarkjs/remark-slug) and gatsby-remark-autolink-headers (https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-remark-autolink-headers) */
import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils'; import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils';
import visit from 'unist-util-visit';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified'; import type {Transformer} from 'unified';
import type {Heading, Text} from 'mdast'; import type {Heading, Text} from 'mdast';
@ -16,6 +15,7 @@ import type {Heading, Text} from 'mdast';
export default function plugin(): Transformer { export default function plugin(): Transformer {
return async (root) => { return async (root) => {
const {toString} = await import('mdast-util-to-string'); const {toString} = await import('mdast-util-to-string');
const {visit} = await import('unist-util-visit');
const slugs = createSlugger(); const slugs = createSlugger();
visit(root, 'heading', (headingNode: Heading) => { visit(root, 'heading', (headingNode: Heading) => {

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer, Processor} from 'unified'; import type {Transformer, Processor} from 'unified';
import type {Code} from 'mdast'; import type {Code} from 'mdast';
@ -18,19 +17,18 @@ import type {Code} from 'mdast';
// To make theme-classic/src/theme/MDXComponents/Pre work // To make theme-classic/src/theme/MDXComponents/Pre work
// we need to fill two properties that mdx v2 doesn't provide anymore // we need to fill two properties that mdx v2 doesn't provide anymore
export default function codeCompatPlugin(this: Processor): Transformer { export default function codeCompatPlugin(this: Processor): Transformer {
return (root) => { return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'code', (node: Code) => { visit(root, 'code', (node: Code) => {
node.data = node.data || {}; node.data = node.data || {};
node.data.hProperties = node.data.hProperties || {}; node.data.hProperties = node.data.hProperties || {};
// eslint-disable-next-line @typescript-eslint/no-explicit-any node.data.hProperties.metastring = node.meta;
(node.data.hProperties as any).metastring = node.meta;
// Retrocompatible support for live codeblock metastring // Retrocompatible support for live codeblock metastring
// Not really the appropriate place to handle that :s // Not really the appropriate place to handle that :s
// eslint-disable-next-line @typescript-eslint/no-explicit-any node.data.hProperties.live = node.meta?.split(' ').includes('live');
(node.data.hProperties as any).live = node.meta
?.split(' ')
.includes('live');
}); });
}; };
} }

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
import {transformNode} from '../utils'; import {transformNode} from '../utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
@ -17,7 +16,9 @@ import type {Code} from 'mdast';
// https://github.com/facebook/docusaurus/issues/6370), this should be provided // https://github.com/facebook/docusaurus/issues/6370), this should be provided
// by theme-mermaid itself // by theme-mermaid itself
export default function plugin(): Transformer { export default function plugin(): Transformer {
return (root) => { return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'code', (node: Code) => { visit(root, 'code', (node: Code) => {
if (node.lang === 'mermaid') { if (node.lang === 'mermaid') {
// TODO migrate to mdxJsxFlowElement? cf admonitions // TODO migrate to mdxJsxFlowElement? cf admonitions

View file

@ -8,13 +8,16 @@
import {parse, type ParserOptions} from '@babel/parser'; import {parse, type ParserOptions} from '@babel/parser';
import traverse from '@babel/traverse'; import traverse from '@babel/traverse';
import stringifyObject from 'stringify-object'; import stringifyObject from 'stringify-object';
import visit from 'unist-util-visit';
import {toValue} from '../utils'; import {toValue} from '../utils';
import type {Identifier} from '@babel/types'; import type {Identifier} from '@babel/types';
import type {Node, Parent} from 'unist'; import type {Node, Parent} from 'unist';
import type {Heading, Literal} from 'mdast'; import type {Heading, Literal} from 'mdast';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified'; import type {Transformer} from 'unified';
import type {
MdxjsEsm,
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
} from 'mdast-util-mdx';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/ // TODO as of April 2023, no way to import/re-export this ESM type easily :/
// TODO upgrade to TS 5.3 // TODO upgrade to TS 5.3
@ -88,6 +91,8 @@ const plugin: Plugin = function plugin(
return async (root) => { return async (root) => {
const {toString} = await import('mdast-util-to-string'); const {toString} = await import('mdast-util-to-string');
const {visit} = await import('unist-util-visit');
const headings: TOCItem[] = []; const headings: TOCItem[] = [];
visit(root, 'heading', (child: Heading) => { visit(root, 'heading', (child: Heading) => {
@ -100,11 +105,12 @@ const plugin: Plugin = function plugin(
headings.push({ headings.push({
value: toValue(child, toString), value: toValue(child, toString),
id: child.data!.id as string, id: child.data!.id!,
level: child.depth, level: child.depth,
}); });
}); });
const {children} = root as Parent<Literal>;
const {children} = root as Parent;
const targetIndex = await getOrCreateExistingTargetIndex(children, name); const targetIndex = await getOrCreateExistingTargetIndex(children, name);
if (headings?.length) { if (headings?.length) {
@ -115,7 +121,7 @@ const plugin: Plugin = function plugin(
export default plugin; export default plugin;
async function createExportNode(name: string, object: any) { async function createExportNode(name: string, object: any): Promise<MdxjsEsm> {
const {valueToEstree} = await import('estree-util-value-to-estree'); const {valueToEstree} = await import('estree-util-value-to-estree');
return { return {

View file

@ -16,7 +16,6 @@ import {
getFileLoaderUtils, getFileLoaderUtils,
findAsyncSequential, findAsyncSequential,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
import visit from 'unist-util-visit';
import escapeHtml from 'escape-html'; import escapeHtml from 'escape-html';
import sizeOf from 'image-size'; import sizeOf from 'image-size';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
@ -192,6 +191,8 @@ async function processImageNode(target: Target, context: Context) {
export default function plugin(options: PluginOptions): Transformer { export default function plugin(options: PluginOptions): Transformer {
return async (root, vfile) => { return async (root, vfile) => {
const {visit} = await import('unist-util-visit');
const promises: Promise<void>[] = []; const promises: Promise<void>[] = [];
visit(root, 'image', (node: Image, index, parent) => { visit(root, 'image', (node: Image, index, parent) => {
promises.push( promises.push(

View file

@ -15,7 +15,6 @@ import {
getFileLoaderUtils, getFileLoaderUtils,
findAsyncSequential, findAsyncSequential,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
import visit from 'unist-util-visit';
import escapeHtml from 'escape-html'; import escapeHtml from 'escape-html';
import {assetRequireAttributeValue, transformNode} from '../utils'; import {assetRequireAttributeValue, transformNode} from '../utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
@ -175,6 +174,8 @@ async function processLinkNode(target: Target, context: Context) {
export default function plugin(options: PluginOptions): Transformer { export default function plugin(options: PluginOptions): Transformer {
return async (root, vfile) => { return async (root, vfile) => {
const {visit} = await import('unist-util-visit');
const promises: Promise<void>[] = []; const promises: Promise<void>[] = [];
visit(root, 'link', (node: Link, index, parent) => { visit(root, 'link', (node: Link, index, parent) => {
promises.push( promises.push(

View file

@ -6,7 +6,6 @@
*/ */
import path from 'path'; import path from 'path';
import process from 'process'; import process from 'process';
import visit from 'unist-util-visit';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
import {posixPath} from '@docusaurus/utils'; import {posixPath} from '@docusaurus/utils';
import {transformNode} from '../utils'; import {transformNode} from '../utils';
@ -14,7 +13,7 @@ import {transformNode} from '../utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer, Processor, Parent} from 'unified'; import type {Transformer, Processor, Parent} from 'unified';
import type { import type {
Directive, Directives,
TextDirective, TextDirective,
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
} from 'mdast-util-directive'; } from 'mdast-util-directive';
@ -25,7 +24,7 @@ import type {
// import type {Plugin} from 'unified'; // import type {Plugin} from 'unified';
type Plugin = any; // TODO fix this asap type Plugin = any; // TODO fix this asap
type DirectiveType = Directive['type']; type DirectiveType = Directives['type'];
const directiveTypes: DirectiveType[] = [ const directiveTypes: DirectiveType[] = [
'containerDirective', 'containerDirective',
@ -39,7 +38,7 @@ const directivePrefixMap: {[key in DirectiveType]: string} = {
containerDirective: ':::', containerDirective: ':::',
}; };
function formatDirectiveName(directive: Directive) { function formatDirectiveName(directive: Directives) {
const prefix = directivePrefixMap[directive.type]; const prefix = directivePrefixMap[directive.type];
if (!prefix) { if (!prefix) {
throw new Error( throw new Error(
@ -50,13 +49,13 @@ function formatDirectiveName(directive: Directive) {
return `${prefix}${directive.name}`; return `${prefix}${directive.name}`;
} }
function formatDirectivePosition(directive: Directive): string | undefined { function formatDirectivePosition(directive: Directives): string | undefined {
return directive.position?.start return directive.position?.start
? logger.interpolate`number=${directive.position.start.line}:number=${directive.position.start.column}` ? logger.interpolate`number=${directive.position.start.line}:number=${directive.position.start.column}`
: undefined; : undefined;
} }
function formatUnusedDirectiveMessage(directive: Directive) { function formatUnusedDirectiveMessage(directive: Directives) {
const name = formatDirectiveName(directive); const name = formatDirectiveName(directive);
const position = formatDirectivePosition(directive); const position = formatDirectivePosition(directive);
@ -67,7 +66,7 @@ function formatUnusedDirectivesMessage({
directives, directives,
filePath, filePath,
}: { }: {
directives: Directive[]; directives: Directives[];
filePath: string; filePath: string;
}): string { }): string {
const supportUrl = 'https://github.com/facebook/docusaurus/pull/9394'; const supportUrl = 'https://github.com/facebook/docusaurus/pull/9394';
@ -87,7 +86,7 @@ function logUnusedDirectivesWarning({
directives, directives,
filePath, filePath,
}: { }: {
directives: Directive[]; directives: Directives[];
filePath: string; filePath: string;
}) { }) {
if (directives.length > 0) { if (directives.length > 0) {
@ -99,13 +98,13 @@ function logUnusedDirectivesWarning({
} }
} }
function isTextDirective(directive: Directive): directive is TextDirective { function isTextDirective(directive: Directives): directive is TextDirective {
return directive.type === 'textDirective'; return directive.type === 'textDirective';
} }
// A simple text directive is one without any label/props // A simple text directive is one without any label/props
function isSimpleTextDirective( function isSimpleTextDirective(
directive: Directive, directive: Directives,
): directive is TextDirective { ): directive is TextDirective {
if (isTextDirective(directive)) { if (isTextDirective(directive)) {
// Attributes in MDAST = Directive props // Attributes in MDAST = Directive props
@ -118,25 +117,30 @@ function isSimpleTextDirective(
return false; return false;
} }
function transformSimpleTextDirectiveToString(textDirective: Directive) { function transformSimpleTextDirectiveToString(textDirective: Directives) {
transformNode(textDirective, { transformNode(textDirective, {
type: 'text', type: 'text',
value: `:${textDirective.name}`, // We ignore label/props on purpose here value: `:${textDirective.name}`, // We ignore label/props on purpose here
}); });
} }
function isUnusedDirective(directive: Directive) { function isUnusedDirective(directive: Directives) {
// If directive data is set (notably hName/hProperties set by admonitions) // If directive data is set (notably hName/hProperties set by admonitions)
// this usually means the directive has been handled by another plugin // this usually means the directive has been handled by another plugin
return !directive.data; return !directive.data;
} }
const plugin: Plugin = function plugin(this: Processor): Transformer { const plugin: Plugin = function plugin(this: Processor): Transformer {
return (tree, file) => { return async (tree, file) => {
const unusedDirectives: Directive[] = []; const {visit} = await import('unist-util-visit');
visit<Parent>(tree, directiveTypes, (directive: Directive) => { const unusedDirectives: Directives[] = [];
// If directive data is set (notably hName/hProperties set by admonitions)
visit<Parent, DirectiveType[]>(
tree,
directiveTypes,
(directive: Directives) => {
// If directive data is set (hName/hProperties set by admonitions)
// this usually means the directive has been handled by another plugin // this usually means the directive has been handled by another plugin
if (isUnusedDirective(directive)) { if (isUnusedDirective(directive)) {
if (isSimpleTextDirective(directive)) { if (isSimpleTextDirective(directive)) {
@ -145,7 +149,8 @@ const plugin: Plugin = function plugin(this: Processor): Transformer {
unusedDirectives.push(directive); unusedDirectives.push(directive);
} }
} }
}); },
);
// We only enable these warnings for the client compiler // We only enable these warnings for the client compiler
// This avoids emitting duplicate warnings in prod mode // This avoids emitting duplicate warnings in prod mode

View file

@ -74,7 +74,7 @@ function mdxJsxTextElementToHtml(
} }
export function toValue( export function toValue(
node: PhrasingContent | Heading, node: PhrasingContent | Heading | MdxJsxTextElement,
toString: (param: unknown) => string, // TODO weird but works toString: (param: unknown) => string, // TODO weird but works
): string { ): string {
switch (node.type) { switch (node.type) {

View file

@ -19,3 +19,16 @@ declare module 'vfile' {
contentTitle?: string; contentTitle?: string;
} }
} }
declare module 'unist' {
interface Data {
hName?: string;
hProperties?: Record<string, unknown>;
}
}
declare module 'mdast' {
interface HeadingData {
id?: string;
}
}

View file

@ -33,7 +33,7 @@
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"srcset": "^4.0.0", "srcset": "^4.0.0",
"tslib": "^2.6.0", "tslib": "^2.6.0",
"unist-util-visit": "^2.0.3", "unist-util-visit": "^5.0.0",
"utility-types": "^3.10.0", "utility-types": "^3.10.0",
"webpack": "^5.88.1" "webpack": "^5.88.1"
}, },

View file

@ -1,18 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`footnoteIDFixer remark plugin appends a hash to each footnote def/ref 1`] = ` exports[`footnoteIDFixer remark plugin appends a hash to each footnote def/ref 1`] = `
"/*@jsxRuntime automatic @jsxImportSource react*/ "import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
function _createMdxContent(props) { function _createMdxContent(props) {
const _components = Object.assign({ const _components = {
p: "p",
sup: "sup",
a: "a", a: "a",
section: "section",
h2: "h2", h2: "h2",
li: "li",
ol: "ol", ol: "ol",
li: "li" p: "p",
}, props.components); section: "section",
sup: "sup",
...props.components
};
return _jsxs(_Fragment, { return _jsxs(_Fragment, {
children: [_jsxs(_components.p, { children: [_jsxs(_components.p, {
children: ["foo", _jsx(_components.sup, { children: ["foo", _jsx(_components.sup, {
@ -57,9 +57,9 @@ function _createMdxContent(props) {
children: ["/n", _jsxs(_components.p, { children: ["/n", _jsxs(_components.p, {
children: ["foo ", _jsx(_components.a, { children: ["foo ", _jsx(_components.a, {
href: "#user-content-fnref-1-[HASH]", href: "#user-content-fnref-1-[HASH]",
"data-footnote-backref": true, "data-footnote-backref": "",
"aria-label": "Back to reference 1",
className: "data-footnote-backref", className: "data-footnote-backref",
"aria-label": "Back to content",
children: "↩" children: "↩"
})] })]
}), "/n"] }), "/n"]
@ -68,9 +68,9 @@ function _createMdxContent(props) {
children: ["/n", _jsxs(_components.p, { children: ["/n", _jsxs(_components.p, {
children: ["foo ", _jsx(_components.a, { children: ["foo ", _jsx(_components.a, {
href: "#user-content-fnref-2-[HASH]", href: "#user-content-fnref-2-[HASH]",
"data-footnote-backref": true, "data-footnote-backref": "",
"aria-label": "Back to reference 2",
className: "data-footnote-backref", className: "data-footnote-backref",
"aria-label": "Back to content",
children: "↩" children: "↩"
})] })]
}), "/n"] }), "/n"]
@ -79,9 +79,9 @@ function _createMdxContent(props) {
children: ["/n", _jsxs(_components.p, { children: ["/n", _jsxs(_components.p, {
children: ["foo ", _jsx(_components.a, { children: ["foo ", _jsx(_components.a, {
href: "#user-content-fnref-3-[HASH]", href: "#user-content-fnref-3-[HASH]",
"data-footnote-backref": true, "data-footnote-backref": "",
"aria-label": "Back to reference 3",
className: "data-footnote-backref", className: "data-footnote-backref",
"aria-label": "Back to content",
children: "↩" children: "↩"
})] })]
}), "/n"] }), "/n"]
@ -90,12 +90,14 @@ function _createMdxContent(props) {
})] })]
}); });
} }
function MDXContent(props = {}) { export default function MDXContent(props = {}) {
const {wrapper: MDXLayout} = props.components || ({}); const {wrapper: MDXLayout} = props.components || ({});
return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, { return MDXLayout ? _jsx(MDXLayout, {
children: _jsx(_createMdxContent, props) ...props,
})) : _createMdxContent(props); children: _jsx(_createMdxContent, {
...props
})
}) : _createMdxContent(props);
} }
export default MDXContent;
" "
`; `;

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
import {simpleHash} from '@docusaurus/utils'; import {simpleHash} from '@docusaurus/utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified'; import type {Transformer} from 'unified';
@ -18,7 +17,9 @@ import type {FootnoteReference, FootnoteDefinition} from 'mdast';
* unique hash to each reference/definition. * unique hash to each reference/definition.
*/ */
export default function plugin(): Transformer { export default function plugin(): Transformer {
return (root, vfile) => { return async (root, vfile) => {
const {visit} = await import('unist-util-visit');
const suffix = `-${simpleHash(vfile.path!, 6)}`; const suffix = `-${simpleHash(vfile.path!, 6)}`;
visit(root, 'footnoteReference', (node: FootnoteReference) => { visit(root, 'footnoteReference', (node: FootnoteReference) => {
node.identifier += suffix; node.identifier += suffix;

View file

@ -17,16 +17,16 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"mdast-util-mdx": "^2.0.0", "mdast-util-mdx": "^3.0.0",
"npm-to-yarn": "^2.0.0", "npm-to-yarn": "^2.0.0",
"tslib": "^2.6.0", "tslib": "^2.6.0",
"unified": "^10.1.2", "unified": "^11.0.3",
"unist-util-visit": "^2.0.3" "unist-util-visit": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/mdast": "^3.0.12", "@types/mdast": "^4.0.2",
"remark": "^14.0.3", "remark": "^15.0.1",
"remark-mdx": "^2.1.5", "remark-mdx": "^3.0.0",
"to-vfile": "^6.1.0" "to-vfile": "^6.1.0"
}, },
"engines": { "engines": {

View file

@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit';
import npmToYarn from 'npm-to-yarn'; import npmToYarn from 'npm-to-yarn';
import type {Code, Literal} from 'mdast'; import type {Code, Literal} from 'mdast';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721 // @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
@ -173,7 +172,9 @@ function createImportNode() {
const plugin: Plugin<[PluginOptions?]> = (options = {}): Transformer => { const plugin: Plugin<[PluginOptions?]> = (options = {}): Transformer => {
// @ts-expect-error: todo temporary // @ts-expect-error: todo temporary
const {sync = false, converters = ['yarn', 'pnpm']} = options; const {sync = false, converters = ['yarn', 'pnpm']} = options;
return (root) => { return async (root) => {
const {visit} = await import('unist-util-visit');
let transformed = false; let transformed = false;
let alreadyImported = false; let alreadyImported = false;

View file

@ -32,7 +32,7 @@
"@docusaurus/utils": "3.0.0-rc.0", "@docusaurus/utils": "3.0.0-rc.0",
"@docusaurus/utils-common": "3.0.0-rc.0", "@docusaurus/utils-common": "3.0.0-rc.0",
"@docusaurus/utils-validation": "3.0.0-rc.0", "@docusaurus/utils-validation": "3.0.0-rc.0",
"@mdx-js/react": "^2.1.5", "@mdx-js/react": "^3.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"copy-text-to-clipboard": "^3.2.0", "copy-text-to-clipboard": "^3.2.0",
"infima": "0.2.0-alpha.43", "infima": "0.2.0-alpha.43",

View file

@ -325,6 +325,7 @@ serializers
setaf setaf
setext setext
shiki shiki
shortcodes
showinfo showinfo
sida sida
simen simen

View file

@ -11,7 +11,7 @@ image: ./img/social-card.png
Docusaurus v3 comes with a few **breaking changes**, many of which can be **handled today under Docusaurus v2**. Preparing your site ahead of time can be done incrementally, and will make it easier to upgrade to v3. Docusaurus v3 comes with a few **breaking changes**, many of which can be **handled today under Docusaurus v2**. Preparing your site ahead of time can be done incrementally, and will make it easier to upgrade to v3.
The most important Docusaurus v3 breaking change is the [**upgrade to MDX v2**](https://mdxjs.com/blog/v2/), which will compile your Markdown content more strictly and with subtle differences. The main breaking change is the upgrade from MDX v1 to MDX v3. Read the [**MDX v2**](https://mdxjs.com/blog/v2/) and [**MDX v3**](https://mdxjs.com/blog/v3/) release notes for details. MDX will now compile your Markdown content **more strictly** and with **subtle differences**.
This article will mostly focus on how to prepare your content for this new MDX version, and will also list a few other breaking changes that you can handle today. This article will mostly focus on how to prepare your content for this new MDX version, and will also list a few other breaking changes that you can handle today.
@ -41,19 +41,19 @@ Depending on the complexity of your site, it may be a good idea to adopt the [vi
We also recommend using the `.mdx` extension whenever you use JSX, `import`, or `export` (i.e. MDX features) inside a Markdown file. It is semantically more correct and improves compatibility with external tools (IDEs, formatters, linters, etc.). In future versions of Docusaurus, `.md` files will be parsed as standard [CommonMark](https://commonmark.org/), which does not support these features. In Docusaurus v3, `.md` files keep being compiled as MDX files, but it will be possible to [opt-in for CommonMark](https://github.com/facebook/docusaurus/issues/3018). We also recommend using the `.mdx` extension whenever you use JSX, `import`, or `export` (i.e. MDX features) inside a Markdown file. It is semantically more correct and improves compatibility with external tools (IDEs, formatters, linters, etc.). In future versions of Docusaurus, `.md` files will be parsed as standard [CommonMark](https://commonmark.org/), which does not support these features. In Docusaurus v3, `.md` files keep being compiled as MDX files, but it will be possible to [opt-in for CommonMark](https://github.com/facebook/docusaurus/issues/3018).
## Preparing content for MDX v2 ## Preparing content for MDX v3
MDX is a major dependency of Docusaurus responsible for compiling your `.md` and `.mdx` files to React components. MDX is a major dependency of Docusaurus responsible for compiling your `.md` and `.mdx` files to React components.
MDX v2 is much better, but also comes with changes that probably require you to refactor your content a bit. MDX v2 is stricter, and some components that compiled fine under v1 might now fail to compile under v2, most likely because of `{` and `<` characters. MDX v3 is much better, but also comes with changes that probably require you to refactor your content a bit. MDX v3 is stricter, and some components that compiled fine under v1 might now fail to compile under v3, most likely because of `{` and `<` characters.
Upgrading MDX comes with all the breaking changes documented on the [MDX v2 release blog post](https://mdxjs.com/blog/v2/). The [MDX v2 migration guide](https://mdxjs.com/migrating/v2/) has a section on how to [update MDX files](https://mdxjs.com/migrating/v2/#update-mdx-files) that will be particularly relevant to us. Also make sure to read the [Troubleshooting MDX](https://mdxjs.com/docs/troubleshooting-mdx/) page that can help you interpret common MDX error messages. Upgrading MDX comes with all the breaking changes documented on the [MDX v2](https://mdxjs.com/blog/v2/) and [MDX v3](https://mdxjs.com/blog/v3/) release blog posts. Most breaking changes come from MDX v2. The [MDX v2 migration guide](https://mdxjs.com/migrating/v2/) has a section on how to [update MDX files](https://mdxjs.com/migrating/v2/#update-mdx-files) that will be particularly relevant to us. Also make sure to read the [Troubleshooting MDX](https://mdxjs.com/docs/troubleshooting-mdx/) page that can help you interpret common MDX error messages.
Make sure to also read our updated [**MDX and React**](/docs/3.0.0-rc.0/markdown-features/react) documentation page. Make sure to also read our updated [**MDX and React**](/docs/3.0.0-rc.0/markdown-features/react) documentation page.
:::tip Ask for help :::tip Ask for help
We have a dedicated [MDX v2 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9053) discussion. We have a dedicated [MDX v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9053) discussion.
::: :::
@ -63,23 +63,23 @@ The MDX playground is your new best friend. It permits to understand how your co
Each MDX version comes with its own playground: Each MDX version comes with its own playground:
- [MDX v1 playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground/) - [MDX playground - current version](https://mdxjs.com/playground/)
- [MDX v2 playground](https://mdxjs.com/playground/) - [MDX playground - v1](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground/)
<details> <details>
<summary>Configuring MDX v2 playground options for Docusaurus</summary> <summary>Configuring the MDX playground options for Docusaurus</summary>
To obtain a compilation behavior similar to what Docusaurus v2 uses, please turn on these options on the [MDX v2 playground](https://mdxjs.com/playground/): To obtain a compilation behavior similar to what Docusaurus v2 uses, please turn on these options on the [MDX playground](https://mdxjs.com/playground/):
- Use `MDX` - Use `MDX`
- Use `remark-gfm` - Use `remark-gfm`
- Use `remark-directive` - Use `remark-directive`
![Screenshot of the MDX v2 playground's options panel, with only the "Use `MDX`", "Use `remark-gfm`", and "Use `remark-directive`" options checked](./img/mdx2-playground-options.png) ![Screenshot of the MDX playground's options panel, with only the "Use `MDX`", "Use `remark-gfm`", and "Use `remark-directive`" options checked](./img/mdx2-playground-options.png)
</details> </details>
Using the two MDX playgrounds side-by-side, you will soon notice that some content is compiled differently or fails to compile in v2. Using the two MDX playgrounds side-by-side, you will soon notice that some content is compiled differently or fails to compile in v3.
:::tip Making your content future-proof :::tip Making your content future-proof
@ -89,7 +89,7 @@ The goal will be to refactor your problematic content so that it **works fine wi
### Using the MDX checker CLI ### Using the MDX checker CLI
We provide a [docusaurus-mdx-checker](https://github.com/slorber/docusaurus-mdx-checker) CLI that permits to easily spot problematic content. Run this command today on your Docusaurus v2 site to obtain a list of files that will fail to compile under MDX v2. We provide a [docusaurus-mdx-checker](https://github.com/slorber/docusaurus-mdx-checker) CLI that permits to easily spot problematic content. Run this command today on your Docusaurus v2 site to obtain a list of files that will fail to compile under MDX v3.
```bash ```bash
npx docusaurus-mdx-checker npx docusaurus-mdx-checker
@ -101,7 +101,7 @@ For each compilation issue, the CLI will log the file path and a line number to
:::tip :::tip
Use this CLI to estimate of how much work will be required to make your content compatible with MDX v2. Use this CLI to estimate of how much work will be required to make your content compatible with MDX v3.
::: :::
@ -115,7 +115,7 @@ It will not report subtle compilation changes that do not produce errors but can
### Common MDX problems ### Common MDX problems
We upgraded a few Docusaurus sites to Docusaurus v3 and MDX v2: We upgraded a few Docusaurus sites to Docusaurus v3 and MDX v3:
- [Docusaurus PR](https://github.com/facebook/docusaurus/pull/8288) - [Docusaurus PR](https://github.com/facebook/docusaurus/pull/8288)
- [React-Native PR](https://github.com/facebook/react-native-website/pull/3780) - [React-Native PR](https://github.com/facebook/react-native-website/pull/3780)
@ -125,7 +125,7 @@ These upgrades permitted us to aggregate the most common content problems, and d
#### Bad usage of `{` #### Bad usage of `{`
The `{` character is used for opening [JavaScript expressions](https://mdxjs.com/docs/what-is-mdx/#expressions). MDX v2 will now fail if what you put inside `{expression}` is not a valid expression. The `{` character is used for opening [JavaScript expressions](https://mdxjs.com/docs/what-is-mdx/#expressions). MDX will now fail if what you put inside `{expression}` is not a valid expression.
```md title="example.md" ```md title="example.md"
The object shape looks like {username: string, age: number} The object shape looks like {username: string, age: number}
@ -149,7 +149,7 @@ Available options to fix this error:
#### Bad usage of `<` #### Bad usage of `<`
The `<` character is used for opening [JSX tags](https://mdxjs.com/docs/what-is-mdx/#jsx). MDX v2 will now fail if it thinks your JSX is invalid. The `<` character is used for opening [JSX tags](https://mdxjs.com/docs/what-is-mdx/#jsx). MDX will now fail if it thinks your JSX is invalid.
```md title="example.md" ```md title="example.md"
Use Android version <5 Use Android version <5
@ -181,7 +181,7 @@ Available options to fix this error:
#### Bad usage of GFM Autolink #### Bad usage of GFM Autolink
Docusaurus supports [GitHub Flavored Markdown (GFM)](https://github.github.com/gfm/), but [autolink](https://github.github.com/gfm/#autolinks) using the `<link>` syntax is not supported anymore by MDX v2. Docusaurus supports [GitHub Flavored Markdown (GFM)](https://github.github.com/gfm/), but [autolink](https://github.github.com/gfm/#autolinks) using the `<link>` syntax is not supported anymore by MDX.
```md title="example.md" ```md title="example.md"
<sebastien@thisweekinreact.com> <sebastien@thisweekinreact.com>
@ -246,11 +246,11 @@ For any other element, **use upper-case names**.
#### Unintended extra paragraphs #### Unintended extra paragraphs
In MDX v2, it is now possible to interleave JSX and Markdown more easily without requiring extra line breaks. Writing content on multiple lines can also produce new expected `<p>` tags. In MDX, it is now possible to interleave JSX and Markdown more easily without requiring extra line breaks. Writing content on multiple lines can also produce new expected `<p>` tags.
:::danger visual difference :::danger visual difference
See how this content is rendered differently by MDX v1 and v2. See how this content is rendered differently by MDX v1 and v3.
```md title="example.md" ```md title="example.md"
<div>Some **Markdown** content</div> <div>Some **Markdown** content</div>
@ -266,7 +266,7 @@ See how this content is rendered differently by MDX v1 and v2.
``` ```
{/* prettier-ignore */} {/* prettier-ignore */}
```html title="MDX v2 output" ```html title="MDX v3 output"
<div>Some <strong>Markdown</strong> content</div> <div>Some <strong>Markdown</strong> content</div>
<div><p>Some <strong>Markdown</strong> content</p></div></div> <div><p>Some <strong>Markdown</strong> content</p></div></div>
``` ```
@ -334,7 +334,7 @@ conf is great
#### Unsupported indented code blocks #### Unsupported indented code blocks
MDX v2 does not transform indented text as code blocks anymore. MDX does not transform indented text as code blocks anymore.
```md title="example.md" ```md title="example.md"
console.log("hello"); console.log("hello");
@ -342,7 +342,7 @@ MDX v2 does not transform indented text as code blocks anymore.
:::danger Visual change :::danger Visual change
The upgrade does not generally produce new MDX v2 compilation errors, but can lead to content being rendered in an unexpected way because there isn't a code block anymore. The upgrade does not generally produce new MDX compilation errors, but can lead to content being rendered in an unexpected way because there isn't a code block anymore.
::: :::
@ -543,7 +543,7 @@ For most sites, the upgrade should be easy. If you prepared your site ahead of t
- "@mdx-js/react": "^1.6.22", - "@mdx-js/react": "^1.6.22",
+ "@docusaurus/core": "3.0.0-beta.0", + "@docusaurus/core": "3.0.0-beta.0",
+ "@docusaurus/preset-classic": "3.0.0-beta.0", + "@docusaurus/preset-classic": "3.0.0-beta.0",
+ "@mdx-js/react": "^2.3.0", + "@mdx-js/react": "^3.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5", "prism-react-renderer": "^1.3.5",
- "react": "^17.0.2", - "react": "^17.0.2",
@ -564,9 +564,9 @@ We will be there to help you upgrade through the following support channels:
- [Docusaurus v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9336) - [Docusaurus v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9336)
- [Docusaurus v3 - Discord channel #migration-v2-to-v3](https://discord.com/channels/398180168688074762/1154771869094912090) - [Docusaurus v3 - Discord channel #migration-v2-to-v3](https://discord.com/channels/398180168688074762/1154771869094912090)
- [MDX v2 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9053) - [MDX v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9053)
- [MDX v2 - Remark/Rehype Plugins Support](https://github.com/facebook/docusaurus/discussions/9337) - [MDX v3 - Remark/Rehype Plugins Support](https://github.com/facebook/docusaurus/discussions/9337)
- [MDX v2 - Discord channel #migration-mdx-v2](https://discord.com/channels/398180168688074762/1116724556976111616) - [MDX v3 - Discord channel #migration-mdx-v3](https://discord.com/channels/398180168688074762/1116724556976111616)
Alternatively, you can look for a paid [Docusaurus Service Provider](https://github.com/facebook/docusaurus/discussions/9281) to execute this upgrade for you. If your site is open source, you can also ask our community for [free, benevolent help](https://github.com/facebook/docusaurus/discussions/9283). Alternatively, you can look for a paid [Docusaurus Service Provider](https://github.com/facebook/docusaurus/discussions/9281) to execute this upgrade for you. If your site is open source, you can also ask our community for [free, benevolent help](https://github.com/facebook/docusaurus/discussions/9283).

View file

@ -21,7 +21,7 @@ This article introduces a **visual regression testing** workflow based on [**Git
This workflow has been tested while upgrading Docusaurus v2 to v3, and already helped catch a few visual regressions on sites such as [React Native](https://reactnative.dev/), [Jest](https://jestjs.io/), and the [Docusaurus](https://docusaurus.io/) site itself. This workflow has been tested while upgrading Docusaurus v2 to v3, and already helped catch a few visual regressions on sites such as [React Native](https://reactnative.dev/), [Jest](https://jestjs.io/), and the [Docusaurus](https://docusaurus.io/) site itself.
Docusaurus v3 comes with infrastructure changes and major dependency upgrades such as [MDX v2](https://mdxjs.com/blog/v2/) and [React 18](https://react.dev/blog/2022/03/29/react-v18), which can produce unexpected side effects. It would have been difficult to notice all the visual regressions without such a workflow. That's why we encourage site owners to consider adopting visual regression testing, especially for highly customized sites. Docusaurus v3 comes with infrastructure changes and major dependency upgrades such as [MDX v3](https://mdxjs.com/blog/v3/) and [React 18](https://react.dev/blog/2022/03/29/react-v18), which can produce unexpected side effects. It would have been difficult to notice all the visual regressions without such a workflow. That's why we encourage site owners to consider adopting visual regression testing, especially for highly customized sites.
## Workflow overview ## Workflow overview

View file

@ -459,7 +459,7 @@ export default {
| `format` | `'mdx' \| 'md' \| 'detect'` | `'mdx'` | The default parser format to use for Markdown content. Using 'detect' will select the appropriate format automatically based on file extensions: `.md` vs `.mdx`. | | `format` | `'mdx' \| 'md' \| 'detect'` | `'mdx'` | The default parser format to use for Markdown content. Using 'detect' will select the appropriate format automatically based on file extensions: `.md` vs `.mdx`. |
| `mermaid` | `boolean` | `false` | When `true`, allows Docusaurus to render Markdown code blocks with `mermaid` language as Mermaid diagrams. | | `mermaid` | `boolean` | `false` | When `true`, allows Docusaurus to render Markdown code blocks with `mermaid` language as Mermaid diagrams. |
| `preprocessor` | `MarkdownPreprocessor` | `undefined` | Gives you the ability to alter the Markdown content string before parsing. Use it as a last-resort escape hatch or workaround: it is almost always better to implement a Remark/Rehype plugin. | | `preprocessor` | `MarkdownPreprocessor` | `undefined` | Gives you the ability to alter the Markdown content string before parsing. Use it as a last-resort escape hatch or workaround: it is almost always better to implement a Remark/Rehype plugin. |
| `mdx1Compat` | `MDX1CompatOptions` | `{comments: true, admonitions: true, headingIds: true}` | Compatibility options to make it easier to upgrade to Docusaurus v3+. See the [MDX 2 PR for details](https://github.com/facebook/docusaurus/pull/8288). | | `mdx1Compat` | `MDX1CompatOptions` | `{comments: true, admonitions: true, headingIds: true}` | Compatibility options to make it easier to upgrade to Docusaurus v3+. |
```mdx-code-block ```mdx-code-block
</APITable> </APITable>

View file

@ -54,12 +54,12 @@ $$
To enable KaTeX, you need to install `remark-math` and `rehype-katex` plugins. To enable KaTeX, you need to install `remark-math` and `rehype-katex` plugins.
```bash npm2yarn ```bash npm2yarn
npm install --save remark-math@5 rehype-katex@6 npm install --save remark-math@6 rehype-katex@7
``` ```
:::warning :::warning
Make sure to use `remark-math >= 5` and `rehype-katex >= 6` for Docusaurus v3 (using MDX v2). Make sure to use `remark-math 6` and `rehype-katex 7` for Docusaurus v3 (using MDX v3). We can't guarantee other versions will work.
::: :::

View file

@ -13,7 +13,7 @@ import TabItem from '@theme/TabItem';
import styles from './markdown-features-react.module.css'; import styles from './markdown-features-react.module.css';
``` ```
Docusaurus has built-in support for [MDX v2](https://mdxjs.com/), which allows you to write JSX within your Markdown files and render them as React components. Docusaurus has built-in support for [MDX](https://mdxjs.com/), which allows you to write JSX within your Markdown files and render them as React components.
Check out the [MDX docs](https://mdxjs.com/) to see what fancy stuff you can do with MDX. Check out the [MDX docs](https://mdxjs.com/) to see what fancy stuff you can do with MDX.
@ -194,7 +194,7 @@ I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> e
We use **upper-case** tag names like `Highlight` on purpose. We use **upper-case** tag names like `Highlight` on purpose.
From MDX v2+ onward (Docusaurus v3+), lower-case tag names are always rendered as native html elements, and will not use any component mapping you provide. From MDX v3+ onward (Docusaurus v3+), lower-case tag names are always rendered as native html elements, and will not use any component mapping you provide.
::: :::
@ -227,7 +227,7 @@ If you don't wrap your imported MDX with `MDXContent`, the global scope will not
### Markdown and JSX interoperability {#markdown-and-jsx-interoperability} ### Markdown and JSX interoperability {#markdown-and-jsx-interoperability}
Docusaurus v3 is using [MDX v2](https://mdxjs.com/blog/v2/). Docusaurus v3 is using [MDX v3](https://mdxjs.com/blog/v3/).
The [MDX syntax](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) is mostly compatible with [CommonMark](https://commonmark.org/), but is much stricter because your `.mdx` files can use JSX and are compiled into real React components (check the [playground](https://mdxjs.com/playground/)). The [MDX syntax](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) is mostly compatible with [CommonMark](https://commonmark.org/), but is much stricter because your `.mdx` files can use JSX and are compiled into real React components (check the [playground](https://mdxjs.com/playground/)).

View file

@ -11,7 +11,7 @@ Docusaurus v3 is a new **major version**, including **breaking changes** requiri
This is not a full rewrite, and the breaking changes are relatively easy to handle. The simplest sites will eventually upgrade by simply updating their npm dependencies. This is not a full rewrite, and the breaking changes are relatively easy to handle. The simplest sites will eventually upgrade by simply updating their npm dependencies.
The main breaking change is the [**upgrade to MDX v2**](https://mdxjs.com/blog/v2/), which will compile your Markdown content **more strictly** and with **subtle differences**. The main breaking change is the upgrade from MDX v1 to MDX v3. Read the [**MDX v2**](https://mdxjs.com/blog/v2/) and [**MDX v3**](https://mdxjs.com/blog/v3/) release notes for details. MDX will now compile your Markdown content **more strictly** and with **subtle differences**.
:::tip Before upgrading :::tip Before upgrading
@ -35,10 +35,11 @@ Docusaurus v3 now uses the following dependencies:
- Node.js v18.0+ - Node.js v18.0+
- React v18.0+ - React v18.0+
- MDX v2.0+ - MDX v3.0+
- TypeScript v5.0+ - TypeScript v5.0+
- prism-react-renderer v2.0+ - prism-react-renderer v2.0+
- react-live v4.0+ - react-live v4.0+
- remark-emoji v4.0+
- mermaid v10.4+ - mermaid v10.4+
:::warning Upgrading community plugins :::warning Upgrading community plugins
@ -61,7 +62,7 @@ A typical `package.json` dependency upgrade example:
+ "@docusaurus/preset-classic": "3.0.0", + "@docusaurus/preset-classic": "3.0.0",
// upgrade to MDX v2 // upgrade to MDX v2
- "@mdx-js/react": "^1.6.22", - "@mdx-js/react": "^1.6.22",
+ "@mdx-js/react": "^2.3.0", + "@mdx-js/react": "^3.0.0",
// upgrade to prism-react-renderer v2.0+ // upgrade to prism-react-renderer v2.0+
- "prism-react-renderer": "^1.3.5", - "prism-react-renderer": "^1.3.5",
+ "prism-react-renderer": "^2.1.0", + "prism-react-renderer": "^2.1.0",
@ -108,7 +109,7 @@ For TypeScript users:
MDX is a major dependency of Docusaurus responsible for compiling your `.md` and `.mdx` files to React components. MDX is a major dependency of Docusaurus responsible for compiling your `.md` and `.mdx` files to React components.
The transition from MDX v1 to MDX v2 is the **main challenge** to the adoption of Docusaurus v3. The transition from MDX v1 to MDX v3 is the **main challenge** to the adoption of Docusaurus v3. Most breaking changes come from MDX v2, and MDX v3 is a relatively small release.
Some documents that compiled successfully under Docusaurus v2 might now **fail to compile** under Docusaurus v3. Some documents that compiled successfully under Docusaurus v2 might now **fail to compile** under Docusaurus v3.
@ -128,7 +129,7 @@ For large sites where a manual review of all pages is complicated, we recommend
::: :::
Upgrading MDX comes with all the breaking changes documented on the [MDX v2 release blog post](https://mdxjs.com/blog/v2/). The [MDX v2 migration guide](https://mdxjs.com/migrating/v2/) has a section on how to [update MDX files](https://mdxjs.com/migrating/v2/#update-mdx-files) that will be particularly relevant to us. Also make sure to read the [Troubleshooting MDX](https://mdxjs.com/docs/troubleshooting-mdx/) page that can help you interpret common MDX error messages. Upgrading MDX comes with all the breaking changes documented on the [MDX v2](https://mdxjs.com/blog/v2/) and [MDX v3](https://mdxjs.com/blog/v3/) release blog posts. Most breaking changes come from MDX v2. The [MDX v2 migration guide](https://mdxjs.com/migrating/v2/) has a section on how to [update MDX files](https://mdxjs.com/migrating/v2/#update-mdx-files) that will be particularly relevant to us. Also make sure to read the [Troubleshooting MDX](https://mdxjs.com/docs/troubleshooting-mdx/) page that can help you interpret common MDX error messages.
Make sure to also read our updated [**MDX and React**](../guides/markdown-features/markdown-features-react.mdx) documentation page. Make sure to also read our updated [**MDX and React**](../guides/markdown-features/markdown-features-react.mdx) documentation page.
@ -136,21 +137,19 @@ Make sure to also read our updated [**MDX and React**](../guides/markdown-featur
The MDX playground is your new best friend. It permits to understand how your content is **compiled to React components**, and troubleshoot compilation or rendering issues in isolation. The MDX playground is your new best friend. It permits to understand how your content is **compiled to React components**, and troubleshoot compilation or rendering issues in isolation.
Each MDX version comes with its own playground: - [MDX playground - current version](https://mdxjs.com/playground/)
- [MDX playground - v1](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground/)
- [MDX v1 playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground/)
- [MDX v2 playground](https://mdxjs.com/playground/)
<details> <details>
<summary>Configuring the MDX v2 playground options for Docusaurus</summary> <summary>Configuring the MDX playground options for Docusaurus</summary>
To obtain a compilation behavior similar to what Docusaurus v2 uses, please turn on these options on the [MDX v2 playground](https://mdxjs.com/playground/): To obtain a compilation behavior similar to what Docusaurus v2 uses, please turn on these options on the [MDX playground](https://mdxjs.com/playground/):
- Use `MDX` - Use `MDX`
- Use `remark-gfm` - Use `remark-gfm`
- Use `remark-directive` - Use `remark-directive`
![Screenshot of the MDX v2 playground's options panel, with only the "Use `MDX`", "Use `remark-gfm`", and "Use `remark-directive`" options checked](@site/blog/2023-09-29-preparing-your-site-for-docusaurus-v3/img/mdx2-playground-options.png) ![Screenshot of the MDX playground's options panel, with only the "Use `MDX`", "Use `remark-gfm`", and "Use `remark-directive`" options checked](@site/blog/2023-09-29-preparing-your-site-for-docusaurus-v3/img/mdx2-playground-options.png)
</details> </details>
@ -164,7 +163,7 @@ The goal will be to refactor your problematic content so that it **works fine wi
### Using the MDX checker CLI ### Using the MDX checker CLI
We provide a [docusaurus-mdx-checker](https://github.com/slorber/docusaurus-mdx-checker) CLI that permits to easily spot problematic content. Run this command on your site to obtain a list of files that will fail to compile under MDX v2. We provide a [docusaurus-mdx-checker](https://github.com/slorber/docusaurus-mdx-checker) CLI that permits to easily spot problematic content. Run this command on your site to obtain a list of files that will fail to compile under MDX v3.
```bash ```bash
npx docusaurus-mdx-checker npx docusaurus-mdx-checker
@ -176,7 +175,7 @@ For each compilation issue, the CLI will log the file path and a line number to
:::tip :::tip
Use this CLI to estimate of how much work will be required to make your content compatible with MDX v2. Use this CLI to estimate of how much work will be required to make your content compatible with MDX v3.
::: :::
@ -190,13 +189,13 @@ It will not report subtle compilation changes that do not produce errors but can
### Common MDX problems ### Common MDX problems
Docusaurus cannot document exhaustively all the changes coming with MDX v2. That's the responsibility of the [MDX v2 migration guide](https://mdxjs.com/migrating/v2/). Docusaurus cannot document exhaustively all the changes coming with MDX. That's the responsibility of the [MDX v2](https://mdxjs.com/migrating/v2/) and [MDX v3](https://mdxjs.com/migrating/v3/) migration guides.
However, by upgrading a few Docusaurus sites, we noticed that most of the issues come down to only a few cases that we have documented for you. However, by upgrading a few Docusaurus sites, we noticed that most of the issues come down to only a few cases that we have documented for you.
#### Bad usage of `{` #### Bad usage of `{`
The `{` character is used for opening [JavaScript expressions](https://mdxjs.com/docs/what-is-mdx/#expressions). MDX v2 will now fail if what you put inside `{expression}` is not a valid expression. The `{` character is used for opening [JavaScript expressions](https://mdxjs.com/docs/what-is-mdx/#expressions). MDX will now fail if what you put inside `{expression}` is not a valid expression.
```md title="example.md" ```md title="example.md"
The object shape looks like {username: string, age: number} The object shape looks like {username: string, age: number}
@ -220,7 +219,7 @@ Available options to fix this error:
#### Bad usage of `<` #### Bad usage of `<`
The `<` character is used for opening [JSX tags](https://mdxjs.com/docs/what-is-mdx/#jsx). MDX v2 will now fail if it thinks your JSX is invalid. The `<` character is used for opening [JSX tags](https://mdxjs.com/docs/what-is-mdx/#jsx). MDX will now fail if it thinks your JSX is invalid.
```md title="example.md" ```md title="example.md"
Use Android version <5 Use Android version <5
@ -252,7 +251,7 @@ Available options to fix this error:
#### Bad usage of GFM Autolink #### Bad usage of GFM Autolink
Docusaurus supports [GitHub Flavored Markdown (GFM)](https://github.github.com/gfm/), but [autolink](https://github.github.com/gfm/#autolinks) using the `<link>` syntax is not supported anymore by MDX v2. Docusaurus supports [GitHub Flavored Markdown (GFM)](https://github.github.com/gfm/), but [autolink](https://github.github.com/gfm/#autolinks) using the `<link>` syntax is not supported anymore by MDX.
```md title="example.md" ```md title="example.md"
<sebastien@thisweekinreact.com> <sebastien@thisweekinreact.com>
@ -317,11 +316,11 @@ For any other element, **use upper-case names**.
#### Unintended extra paragraphs #### Unintended extra paragraphs
In MDX v2, it is now possible to interleave JSX and Markdown more easily without requiring extra line breaks. Writing content on multiple lines can also produce new expected `<p>` tags. In MDX v3, it is now possible to interleave JSX and Markdown more easily without requiring extra line breaks. Writing content on multiple lines can also produce new expected `<p>` tags.
:::danger visual difference :::danger visual difference
See how this content is rendered differently by MDX v1 and v2. See how this content is rendered differently by MDX v1 and v3.
```md title="example.md" ```md title="example.md"
<div>Some **Markdown** content</div> <div>Some **Markdown** content</div>
@ -337,7 +336,7 @@ See how this content is rendered differently by MDX v1 and v2.
``` ```
{/* prettier-ignore */} {/* prettier-ignore */}
```html title="MDX v2 output" ```html title="MDX v3 output"
<div>Some <strong>Markdown</strong> content</div> <div>Some <strong>Markdown</strong> content</div>
<div><p>Some <strong>Markdown</strong> content</p></div></div> <div><p>Some <strong>Markdown</strong> content</p></div></div>
``` ```
@ -403,7 +402,7 @@ conf is great
#### Unsupported indented code blocks #### Unsupported indented code blocks
MDX v2 does not transform indented text as code blocks anymore. MDX does not transform indented text as code blocks anymore.
```md title="example.md" ```md title="example.md"
console.log("hello"); console.log("hello");
@ -411,7 +410,7 @@ MDX v2 does not transform indented text as code blocks anymore.
:::danger Visual change :::danger Visual change
The upgrade does not generally produce new MDX v2 compilation errors, but can lead to content being rendered in an unexpected way because there isn't a code block anymore. The upgrade does not generally produce new MDX compilation errors, but can lead to content being rendered in an unexpected way because there isn't a code block anymore.
::: :::
@ -467,7 +466,7 @@ If you created custom Remark or Rehype plugins, you may need to refactor those,
## Other Breaking Changes ## Other Breaking Changes
Apart the MDX v2 upgrade, here is an exhaustive list of breaking changes coming with Docusaurus v3. Apart the MDX v3 upgrade, here is an exhaustive list of breaking changes coming with Docusaurus v3.
### Node.js v18.0 ### Node.js v18.0
@ -578,6 +577,18 @@ However, this is a new major library version containing breaking changes, and we
::: :::
### remark-emoji v4.0+
Docusaurus v3 upgrades [`prism-react-renderer`](https://github.com/rhysd/remark-emoji) to v4.0+. This library is to support `:emoji:` shortcuts in Markdown.
:::info How to upgrade
Most Docusaurus users have nothing to do. Users of emoji shortcodes should read the [changelog](https://github.com/rhysd/remark-emoji/blob/master/CHANGELOG.md) and double-check their emojis keep rendering as expected.
> **Breaking Change** Update [node-emoji](https://www.npmjs.com/package/node-emoji) from v1 to v2. This change introduces support for many new emojis and removes old emoji short codes which are no longer valid on GitHub.
:::
### Mermaid v10.4+ ### Mermaid v10.4+
For users of the `@docusaurus/theme-mermaid` package, Docusaurus v3 upgrades [`mermaid`](https://github.com/mermaid-js/mermaid) to v10.4+. For users of the `@docusaurus/theme-mermaid` package, Docusaurus v3 upgrades [`mermaid`](https://github.com/mermaid-js/mermaid) to v10.4+.
@ -800,11 +811,26 @@ We recommend using the `.mdx` extension whenever you use JSX, `import`, or `expo
In future versions of Docusaurus, `.md` files will be parsed as standard [CommonMark](https://commonmark.org/), which does not support these features. In Docusaurus v3, `.md` files keep being compiled as MDX files, but it will be possible to [opt-in for CommonMark](https://github.com/facebook/docusaurus/issues/3018). In future versions of Docusaurus, `.md` files will be parsed as standard [CommonMark](https://commonmark.org/), which does not support these features. In Docusaurus v3, `.md` files keep being compiled as MDX files, but it will be possible to [opt-in for CommonMark](https://github.com/facebook/docusaurus/issues/3018).
### Upgrading math packages
If you use Docusaurus to render [Math Equations](../guides/markdown-features/markdown-features-math-equations.mdx), you should upgrade the MDX plugins.
Make sure to use `remark-math 6` and `rehype-katex 7` for Docusaurus v3 (using MDX v3). We can't guarantee other versions will work.
```diff package.json
{
- "remark-math": "^3.0.0",
+ "remark-math": "^6.0.0",
- "rehype-katex": "^5.0.0"
+ "rehype-katex": "^7.0.0"
}
```
## Ask For Help ## Ask For Help
In case of any upgrade problem, the first things to try are: In case of any upgrade problem, the first things to try are:
- make sure all your docs compile in the [MDX v2 playground](https://mdxjs.com/playground/), or using [`npx docusaurus-mdx-checker`](https://github.com/slorber/docusaurus-mdx-checker) - make sure all your docs compile in the [MDX playground](https://mdxjs.com/playground/), or using [`npx docusaurus-mdx-checker`](https://github.com/slorber/docusaurus-mdx-checker)
- delete `node_modules` and run `npm install` again - delete `node_modules` and run `npm install` again
- run `docusaurus clear` to clear the caches - run `docusaurus clear` to clear the caches
- remove third-party plugins that might not support Docusaurus v3 - remove third-party plugins that might not support Docusaurus v3
@ -814,9 +840,9 @@ Once you have tried that, you can ask for support through the following support
- [Docusaurus v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9336) - [Docusaurus v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9336)
- [Docusaurus v3 - Discord channel #migration-v2-to-v3](https://discord.com/channels/398180168688074762/1154771869094912090) - [Docusaurus v3 - Discord channel #migration-v2-to-v3](https://discord.com/channels/398180168688074762/1154771869094912090)
- [MDX v2 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9053) - [MDX v3 - Upgrade Support](https://github.com/facebook/docusaurus/discussions/9053)
- [MDX v2 - Remark/Rehype Plugins Support](https://github.com/facebook/docusaurus/discussions/9337) - [MDX v3 - Remark/Rehype Plugins Support](https://github.com/facebook/docusaurus/discussions/9337)
- [MDX v2 - Discord channel #migration-mdx-v2](https://discord.com/channels/398180168688074762/1116724556976111616) - [MDX v3 - Discord channel #migration-mdx-v3](https://discord.com/channels/398180168688074762/1116724556976111616)
Please consider **our time is precious**. To ensure that your support request is not ignored, we kindly ask you to: Please consider **our time is precious**. To ensure that your support request is not ignored, we kindly ask you to:

View file

@ -62,10 +62,10 @@
"react-lite-youtube-embed": "^2.3.52", "react-lite-youtube-embed": "^2.3.52",
"react-medium-image-zoom": "^5.1.6", "react-medium-image-zoom": "^5.1.6",
"react-popper": "^2.3.0", "react-popper": "^2.3.0",
"rehype-katex": "^6.0.3", "rehype-katex": "^7.0.0",
"remark-math": "^5.1.1", "remark-math": "^6.0.0",
"swc-loader": "^0.2.3", "swc-loader": "^0.2.3",
"unist-util-visit": "^2.0.3", "unist-util-visit": "^5.0.0",
"webpack": "^5.88.1", "webpack": "^5.88.1",
"workbox-routing": "^6.6.1", "workbox-routing": "^6.6.1",
"workbox-strategies": "^6.6.1" "workbox-strategies": "^6.6.1"

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import visit from 'unist-util-visit'; import {visit} from 'unist-util-visit';
/** /**
* Turns a "```js config-tabs" code block into a "plugin options" and a "preset * Turns a "```js config-tabs" code block into a "plugin options" and a "preset

1619
yarn.lock

File diff suppressed because it is too large Load diff