From 7f3ee9b83579e411fe7b44f06f8cb65fec189987 Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Tue, 6 Feb 2024 15:52:20 -0500 Subject: [PATCH] Fix \require to properly handle retries in dependencies. (mathjax/MathJax#3170) --- ts/input/tex/require/RequireConfiguration.ts | 88 +++++++++++++------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/ts/input/tex/require/RequireConfiguration.ts b/ts/input/tex/require/RequireConfiguration.ts index a24374a0c..75b96cac0 100644 --- a/ts/input/tex/require/RequireConfiguration.ts +++ b/ts/input/tex/require/RequireConfiguration.ts @@ -53,36 +53,57 @@ function RegisterExtension(jax: TeX, name: string) { if (required.indexOf(extension) < 0) { required.push(extension); // - // Register any dependencies that were loaded to handle this one + // Register any dependencies that were loaded to handle this one, + // and save the retry promise, if any, for when the dependencies need + // to restart the expression (due to preprocessors, see below). // - RegisterDependencies(jax, LOADERCONFIG.dependencies[name]); + let retry = RegisterDependencies(jax, LOADERCONFIG.dependencies[name]); // - // If the required file loaded an extension... + // If we need to restart the expression due to the dependencies, + // Wait for the dependencies to load, process this extension, then retry, + // Otherwise, process the extension now. // - const handler = ConfigurationHandler.get(extension); - if (handler) { - // - // Check if there are user-supplied options - // (place them in a block for the extension, if needed) - // - let options = MJCONFIG[name] || {}; - if (handler.options && Object.keys(handler.options).length === 1 && handler.options[extension]) { - options = {[extension]: options}; - } - // - // Register the extension with the jax's configuration - // - (jax as any).configuration.add(extension, jax, options); - // - // If there are preprocessors, restart so that they run - // (we don't have access to the document or MathItem needed to call - // the preprocessors from here) - // - const configured = jax.parseOptions.packageData.get('require').configured; - if (handler.preprocessors.length && !configured.has(extension)) { - configured.set(extension, true); - mathjax.retryAfter(Promise.resolve()); - } + if (retry) { + mathjax.retryAfter(retry.then(() => ProcessExtension(jax, name, extension))); + } else { + ProcessExtension(jax, name, extension); + } + } +} + +/** + * Add an extension to the configuration, and configure its user options + * + * @param {TeX} jax The TeX jax whose configuration is to be modified + * @param {string} name The name of the extension being added (e.g., '[tex]/amscd') + */ +function ProcessExtension(jax: TeX, name: string, extension: string) { + // + // If the required file loaded an extension... + // + const handler = ConfigurationHandler.get(extension); + if (handler) { + // + // Check if there are user-supplied options + // (place them in a block for the extension, if needed) + // + let options = MJCONFIG[name] || {}; + if (handler.options && Object.keys(handler.options).length === 1 && handler.options[extension]) { + options = {[extension]: options}; + } + // + // Register the extension with the jax's configuration + // + (jax as any).configuration.add(extension, jax, options); + // + // If there are preprocessors, restart the typesetting so that they run + // (we don't have access to the document or MathItem needed to call + // the preprocessors from here) + // + const configured = jax.parseOptions.packageData.get('require').configured; + if (handler.preprocessors.length && !configured.has(extension)) { + configured.set(extension, true); + mathjax.retryAfter(Promise.resolve()); } } } @@ -92,14 +113,23 @@ function RegisterExtension(jax: TeX, name: string) { * * @param {TeX} jax The jax whose configuration is being modified * @param {string[]} names The names of the dependencies to register + * @return {Promise} A promise resolved when all dependency's retries + * are complete (or null if no retries) */ -function RegisterDependencies(jax: TeX, names: string[] = []) { +function RegisterDependencies(jax: TeX, names: string[] = []): Promise { const prefix = jax.parseOptions.options.require.prefix; + const retries = []; for (const name of names) { if (name.substring(0, prefix.length) === prefix) { - RegisterExtension(jax, name); + try { + RegisterExtension(jax, name); + } catch (err) { + if (!err.retry) throw err; + retries.push(err.retry); + } } } + return (retries.length ? Promise.all(retries) : null); } /**