mirror of
https://github.com/Snigdha-OS/documentation.git
synced 2025-09-08 19:34:56 +02:00
235 lines
10 KiB
JavaScript
235 lines
10 KiB
JavaScript
/**
|
||
* @typedef {import('estree-jsx').Program} Program
|
||
* @typedef {import('hast-util-to-estree').ElementAttributeNameCase} ElementAttributeNameCase
|
||
* @typedef {import('hast-util-to-estree').StylePropertyNameCase} StylePropertyNameCase
|
||
* @typedef {import('mdast').Root} Root
|
||
* @typedef {import('remark-rehype').Options} RemarkRehypeOptions
|
||
* @typedef {typeof import('source-map').SourceMapGenerator} SourceMapGenerator
|
||
* @typedef {import('unified').PluggableList} PluggableList
|
||
* @typedef {import('unified').Processor<Root, Program, Program, Program, string>} Processor
|
||
*/
|
||
|
||
/**
|
||
* @typedef ProcessorOptions
|
||
* Configuration for `createProcessor`.
|
||
* @property {SourceMapGenerator | null | undefined} [SourceMapGenerator]
|
||
* Add a source map (object form) as the `map` field on the resulting file
|
||
* (optional).
|
||
* @property {URL | string | null | undefined} [baseUrl]
|
||
* Use this URL as `import.meta.url` and resolve `import` and `export … from`
|
||
* relative to it (optional, example: `import.meta.url`).
|
||
* @property {boolean | null | undefined} [development=false]
|
||
* Whether to add extra info to error messages in generated code and use the
|
||
* development automatic JSX runtime (`Fragment` and `jsxDEV` from
|
||
* `/jsx-dev-runtime`) (default: `false`);
|
||
* when using the webpack loader (`@mdx-js/loader`) or the Rollup integration
|
||
* (`@mdx-js/rollup`) through Vite, this is automatically inferred from how
|
||
* you configure those tools.
|
||
* @property {ElementAttributeNameCase | null | undefined} [elementAttributeNameCase='react']
|
||
* Casing to use for attribute names (default: `'react'`);
|
||
* HTML casing is for example `class`, `stroke-linecap`, `xml:lang`;
|
||
* React casing is for example `className`, `strokeLinecap`, `xmlLang`;
|
||
* for JSX components written in MDX, the author has to be aware of which
|
||
* framework they use and write code accordingly;
|
||
* for AST nodes generated by this project, this option configures it
|
||
* @property {'md' | 'mdx' | null | undefined} [format='mdx']
|
||
* format of the file (default: `'mdx'`);
|
||
* `'md'` means treat as markdown and `'mdx'` means treat as MDX.
|
||
* @property {boolean | null | undefined} [jsx=false]
|
||
* Whether to keep JSX (default: `false`);
|
||
* the default is to compile JSX away so that the resulting file is
|
||
* immediately runnable.
|
||
* @property {string | null | undefined} [jsxImportSource='react']
|
||
* Place to import automatic JSX runtimes from (default: `'react'`);
|
||
* when in the `automatic` runtime, this is used to define an import for
|
||
* `Fragment`, `jsx`, `jsxDEV`, and `jsxs`.
|
||
* @property {'automatic' | 'classic' | null | undefined} [jsxRuntime='automatic']
|
||
* JSX runtime to use (default: `'automatic'`);
|
||
* the automatic runtime compiles to `import _jsx from
|
||
* '$importSource/jsx-runtime'\n_jsx('p')`;
|
||
* the classic runtime compiles to calls such as `h('p')`.
|
||
*
|
||
* > 👉 **Note**: support for the classic runtime is deprecated and will
|
||
* > likely be removed in the next major version.
|
||
* @property {ReadonlyArray<string> | null | undefined} [mdExtensions]
|
||
* List of markdown extensions, with dot (default: `['.md', '.markdown', …]`);
|
||
* affects integrations.
|
||
* @property {ReadonlyArray<string> | null | undefined} [mdxExtensions]
|
||
* List of MDX extensions, with dot (default: `['.mdx']`);
|
||
* affects integrations.
|
||
* @property {'function-body' | 'program' | null | undefined} [outputFormat='program']
|
||
* Output format to generate (default: `'program'`);
|
||
* in most cases `'program'` should be used, it results in a whole program;
|
||
* internally `evaluate` uses `'function-body'` to compile to
|
||
* code that can be passed to `run`;
|
||
* in some cases, you might want what `evaluate` does in separate steps, such
|
||
* as when compiling on the server and running on the client.
|
||
* @property {string | null | undefined} [pragma='React.createElement']
|
||
* Pragma for JSX, used in the classic runtime as an identifier for function
|
||
* calls: `<x />` to `React.createElement('x')` (default:
|
||
* `'React.createElement'`);
|
||
* when changing this, you should also define `pragmaFrag` and
|
||
* `pragmaImportSource` too.
|
||
*
|
||
* > 👉 **Note**: support for the classic runtime is deprecated and will
|
||
* > likely be removed in the next major version.
|
||
* @property {string | null | undefined} [pragmaFrag='React.Fragment']
|
||
* Pragma for fragment symbol, used in the classic runtime as an identifier
|
||
* for unnamed calls: `<>` to `React.createElement(React.Fragment)` (default:
|
||
* `'React.Fragment'`);
|
||
* when changing this, you should also define `pragma` and
|
||
* `pragmaImportSource` too.
|
||
*
|
||
* > 👉 **Note**: support for the classic runtime is deprecated and will
|
||
* > likely be removed in the next major version.
|
||
* @property {string | null | undefined} [pragmaImportSource='react']
|
||
* Where to import the identifier of `pragma` from, used in the classic
|
||
* runtime (default: `'react'`);
|
||
* to illustrate, when `pragma` is `'a.b'` and `pragmaImportSource` is `'c'`
|
||
* the following will be generated: `import a from 'c'` and things such as
|
||
* `a.b('h1', {})`.
|
||
* when changing this, you should also define `pragma` and `pragmaFrag` too.
|
||
*
|
||
* > 👉 **Note**: support for the classic runtime is deprecated and will
|
||
* > likely be removed in the next major version.
|
||
* @property {string | null | undefined} [providerImportSource]
|
||
* Place to import a provider from (optional, example: `'@mdx-js/react'`);
|
||
* normally it’s used for runtimes that support context (React, Preact), but
|
||
* it can be used to inject components into the compiled code;
|
||
* the module must export and identifier `useMDXComponents` which is called
|
||
* without arguments to get an object of components (`MDXComponents` from
|
||
* `mdx/types.js`).
|
||
* @property {PluggableList | null | undefined} [recmaPlugins]
|
||
* List of recma plugins (optional);
|
||
* this is a new ecosystem, currently in beta, to transform esast trees
|
||
* (JavaScript)
|
||
* @property {PluggableList | null | undefined} [remarkPlugins]
|
||
* List of remark plugins (optional).
|
||
* @property {PluggableList | null | undefined} [rehypePlugins]
|
||
* List of rehype plugins (optional).
|
||
* @property {Readonly<RemarkRehypeOptions> | null | undefined} [remarkRehypeOptions]
|
||
* Options to pass through to `remark-rehype` (optional);
|
||
* the option `allowDangerousHtml` will always be set to `true` and the MDX
|
||
* nodes (see `nodeTypes`) are passed through;
|
||
* In particular, you might want to pass configuration for footnotes if your
|
||
* content is not in English.
|
||
* @property {StylePropertyNameCase | null | undefined} [stylePropertyNameCase='dom']
|
||
* Casing to use for property names in `style` objects (default: `'dom'`);
|
||
* CSS casing is for example `background-color` and `-webkit-line-clamp`;
|
||
* DOM casing is for example `backgroundColor` and `WebkitLineClamp`;
|
||
* for JSX components written in MDX, the author has to be aware of which
|
||
* framework they use and write code accordingly;
|
||
* for AST nodes generated by this project, this option configures it
|
||
* @property {boolean | null | undefined} [tableCellAlignToStyle=true]
|
||
* Turn obsolete `align` properties on `td` and `th` into CSS `style`
|
||
* properties (default: `true`).
|
||
*/
|
||
|
||
import {unreachable} from 'devlop'
|
||
import remarkMdx from 'remark-mdx'
|
||
import remarkParse from 'remark-parse'
|
||
import remarkRehype from 'remark-rehype'
|
||
import {unified} from 'unified'
|
||
import {recmaDocument} from './plugin/recma-document.js'
|
||
import {recmaJsxBuild} from './plugin/recma-jsx-build.js'
|
||
import {recmaJsxRewrite} from './plugin/recma-jsx-rewrite.js'
|
||
import {recmaStringify} from './plugin/recma-stringify.js'
|
||
import {rehypeRecma} from './plugin/rehype-recma.js'
|
||
import {rehypeRemoveRaw} from './plugin/rehype-remove-raw.js'
|
||
import {remarkMarkAndUnravel} from './plugin/remark-mark-and-unravel.js'
|
||
import {nodeTypes} from './node-types.js'
|
||
|
||
const removedOptions = [
|
||
'compilers',
|
||
'filepath',
|
||
'hastPlugins',
|
||
'mdPlugins',
|
||
'skipExport',
|
||
'wrapExport'
|
||
]
|
||
|
||
let warned = false
|
||
|
||
/**
|
||
* Create a processor to compile markdown or MDX to JavaScript.
|
||
*
|
||
* > **Note**: `format: 'detect'` is not allowed in `ProcessorOptions`.
|
||
*
|
||
* @param {Readonly<ProcessorOptions> | null | undefined} [options]
|
||
* Configuration (optional).
|
||
* @return {Processor}
|
||
* Processor.
|
||
*/
|
||
export function createProcessor(options) {
|
||
const settings = options || {}
|
||
let index = -1
|
||
|
||
while (++index < removedOptions.length) {
|
||
const key = removedOptions[index]
|
||
if (key in settings) {
|
||
unreachable(
|
||
'Unexpected removed option `' +
|
||
key +
|
||
'`; see <https://mdxjs.com/migrating/v2/> on how to migrate'
|
||
)
|
||
}
|
||
}
|
||
|
||
// @ts-expect-error: throw an error for a runtime value which is not allowed
|
||
// by the types.
|
||
if (settings.format === 'detect') {
|
||
unreachable(
|
||
"Unexpected `format: 'detect'`, which is not supported by `createProcessor`, expected `'mdx'` or `'md'`"
|
||
)
|
||
}
|
||
|
||
if (
|
||
(settings.jsxRuntime === 'classic' ||
|
||
settings.pragma ||
|
||
settings.pragmaFrag ||
|
||
settings.pragmaImportSource) &&
|
||
!warned
|
||
) {
|
||
warned = true
|
||
console.warn(
|
||
"Unexpected deprecated option `jsxRuntime: 'classic'`, `pragma`, `pragmaFrag`, or `pragmaImportSource`; see <https://mdxjs.com/migrating/v3/> on how to migrate"
|
||
)
|
||
}
|
||
|
||
const pipeline = unified().use(remarkParse)
|
||
|
||
if (settings.format !== 'md') {
|
||
pipeline.use(remarkMdx)
|
||
}
|
||
|
||
const remarkRehypeOptions = settings.remarkRehypeOptions || {}
|
||
|
||
pipeline
|
||
.use(remarkMarkAndUnravel)
|
||
.use(settings.remarkPlugins || [])
|
||
.use(remarkRehype, {
|
||
...remarkRehypeOptions,
|
||
allowDangerousHtml: true,
|
||
passThrough: [...(remarkRehypeOptions.passThrough || []), ...nodeTypes]
|
||
})
|
||
.use(settings.rehypePlugins || [])
|
||
|
||
if (settings.format === 'md') {
|
||
pipeline.use(rehypeRemoveRaw)
|
||
}
|
||
|
||
pipeline
|
||
.use(rehypeRecma, settings)
|
||
.use(recmaDocument, settings)
|
||
.use(recmaJsxRewrite, settings)
|
||
|
||
if (!settings.jsx) {
|
||
pipeline.use(recmaJsxBuild, settings)
|
||
}
|
||
|
||
pipeline.use(recmaStringify, settings).use(settings.recmaPlugins || [])
|
||
|
||
// @ts-expect-error: we added plugins with if-checks, which TS doesn’t get.
|
||
return pipeline
|
||
}
|