This commit is contained in:
2026-01-19 19:13:27 +01:00
commit 9d0442e88f
4968 changed files with 1142016 additions and 0 deletions

18
node_modules/unist-util-mdx-define/LICENSE.md generated vendored Normal file
View File

@@ -0,0 +1,18 @@
# MIT License
Copyright © 2025 Remco Haszing
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the “Software”), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

129
node_modules/unist-util-mdx-define/README.md generated vendored Normal file
View File

@@ -0,0 +1,129 @@
# unist-util-mdx-define
[![github actions](https://github.com/remcohaszing/unist-util-mdx-define/actions/workflows/ci.yaml/badge.svg)](https://github.com/remcohaszing/unist-util-mdx-define/actions/workflows/ci.yaml)
[![codecov](https://codecov.io/gh/remcohaszing/unist-util-mdx-define/branch/main/graph/badge.svg)](https://codecov.io/gh/remcohaszing/unist-util-mdx-define)
[![npm version](https://img.shields.io/npm/v/unist-util-mdx-define)](https://www.npmjs.com/package/unist-util-mdx-define)
[![npm downloads](https://img.shields.io/npm/dm/unist-util-mdx-define)](https://www.npmjs.com/package/unist-util-mdx-define)
A [unist](https://github.com/syntax-tree/unist) utility to define [MDX](https://mdxjs.com) exports.
## Table of Contents
- [Introduction](#introduction)
- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
- [`define`](#define)
- [Compatibility](#compatibility)
- [Related projects](#related-projects)
- [License](#license)
## Introduction
This package provides a utility to define exports in an [MDX](https://mdxjs.com) AST, so you dont
have to worry about the details. It supports [mdast](https://github.com/syntax-tree/mdast)
([remark](https://github.com/remarkjs)), [hast](https://github.com/syntax-tree/hast)
([rehype](https://github.com/rehypejs)), and [estree](https://github.com/estree/estree) /
[esast](https://github.com/syntax-tree/esast) ([recma](https://github.com/mdx-js/recma)). This
package supports various options to export the variables you define and to handle name conflicts.
## Installation
```sh
npm install unist-util-mdx-define
```
## Usage
Typically this is used with an MDX plugin.
```ts
import { compile } from '@mdx-js/mdx'
import type * as estree from 'estree'
import type * as hast from 'hast'
import type * as mdast from 'mdast'
import { type Plugin } from 'unified'
import { define } from 'unist-util-mdx-define'
const yourRemarkMdxPlugin: Plugin<[], mdast.Root> = () => (ast, file) => {
define(ast, file, { remarkVariable: { type: 'Literal', value: 'Hello remark plugin!' } })
}
const yourRehypeMdxPlugin: Plugin<[], hast.Root> = () => (ast, file) => {
define(ast, file, { rehypeVariable: { type: 'Literal', value: 'Hello rehype plugin!' } })
}
const yourRecmaMdxPlugin: Plugin<[], estree.Program> = () => (ast, file) => {
define(ast, file, { recmaVariable: { type: 'Literal', value: 'Hello recma plugin!' } })
}
const { value } = await compile('{remarkVariable} {rehypeVariable} {recmaVariable}', {
remarkPlugins: [yourRemarkMdxPlugin],
rehypePlugins: [yourRehypeMdxPlugin],
recmaPlugins: [yourRecmaMdxPlugin]
})
console.log(value)
```
MDX remark, rehype, and recma plugins are similar, but not the same. The type of plugin you should
create depends on your goal.
If your goal is to handle something specific to the markdown content, you should write a remark
plugin. A practical example is
[`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter). This plugin
handles frontmatter data, which no longer exists after the mdast is compiled to hast.
If your goal is to transform or access content, you typically want a rehype plugin. A good example
is [`rehype-mdx-title`](https://github.com/remcohaszing/rehype-mdx-title), which accesses the title
of the document.
For most other purposes, use a recma plugin. For example,
[`recma-export-filepath`](https://github.com/remcohaszing/recma-export-filepath) exposes file
information. This doesnt need access to the content.
`unist-util-mdx-define` can define variables in any of these AST types. For mdast and hast, it
prepends the variable declarations to the root. This way theyll end up at the start of the module,
and their value can be used by **user defined** expressions. This does mean the **generated**
expressions are not able to use other variables. For ESTree, `unist-util-mdx-define` attempts to do
the same.
## API
### `define`
Define variables in an MDX related AST.
#### Parameters
- `ast` ([mdast.Root](https://github.com/syntax-tree/mdast#root) |
[hast.Root](https://github.com/syntax-tree/hast#root) |
[estree.Program](https://github.com/estree/estree)) — The AST in which to define an export.
- `file` ([VFile](https://github.com/vfile/vfile)) — The file to emit warnings to.
- `variables` (`Record<string, estree.Expression>`) — A mapping of variables to define. They keys
are the names. The values are the ESTree expression to represent them.
- `options` ([Options](#options)) — Additional options to configure behaviour.
#### Options
- `export` — If and how to export the variable. (Default: `'module'`)
- `'module'`: Export the value using an ESM const export declaration.
- `'namespace'`: Attach the value as a property on `MDXContent`.
- `false`: Define the variable locally, but dont export it.
- `conflict` — What to do if theres a name conflict. (Default: `'throw'`)
- `'skip'`: Dont insert the variable if theres a name conflict.
- `'throw'`: Throw if theres a name conflict.
- `'warn'`: Emit a vfile warning, but dont throw.
## Compatibility
This project is compatible with Node.js 16 or greater.
## Related projects
- [`estree-util-value-to-estree`](https://github.com/remcohaszing/estree-util-value-to-estree) —
Convert a JavaScript value to an estree expression
## License
[MIT](LICENSE.md) © [Remco Haszing](https://github.com/remcohaszing)

View File

@@ -0,0 +1,51 @@
import type * as estree from 'estree';
import type * as hast from 'hast';
import type * as mdast from 'mdast';
import { type VFile } from 'vfile';
export declare namespace define {
/**
* A mapping of variables to define. They keys are the names. The values are the ESTree expression
* to represent them.
*/
type Variables = Record<string, estree.Expression>;
/**
* Options for {@link define}
*/
interface Options {
/**
* If and how to export the variable.
*
* - `'module'`: Export the value using an ESM const export declaration.
* - `'namespace'`: Attach the value as a property on `MDXContent`.
* - `false`: Define the variable locally, but dont export it.
*
* @default 'module'
*/
export?: 'module' | 'namespace' | false | undefined;
/**
* What to do if theres a name conflict.
*
* - `'skip'`: Dont insert the variable if theres a name conflict.
* - `'throw'`: Throw if theres a name conflict.
* - `'warn'`: Emit a vfile warning, but dont throw.
*
* @default 'throw'
*/
conflict?: 'skip' | 'throw' | 'warn' | undefined;
}
}
/**
* Define variables in an MDX related AST.
*
* @param ast
* The AST in which to define an export
* @param file
* The {@link VFile} to emit warnings to.
* @param variables
* A mapping of variables to define. They keys are the names. The values are the ESTree expression
* to represent them.
* @param options
* Additional options to configure behaviour.
*/
export declare function define(ast: estree.Program | hast.Root | mdast.Root, file: VFile, variables: define.Variables, options?: define.Options | undefined): undefined;
//# sourceMappingURL=unist-util-mdx-define.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"unist-util-mdx-define.d.ts","sourceRoot":"","sources":["../src/unist-util-mdx-define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,QAAQ,CAAA;AAIrC,OAAO,KAAK,KAAK,IAAI,MAAM,MAAM,CAAA;AACjC,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,OAAO,CAAA;AAElC,yBAAiB,MAAM,CAAC;IACtB;;;OAGG;IACH,KAAY,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;IAEzD;;OAEG;IACH,UAAiB,OAAO;QACtB;;;;;;;;WAQG;QACH,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,KAAK,GAAG,SAAS,CAAA;QAEnD;;;;;;;;WAQG;QACH,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;KACjD;CACF;AAgLD;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CACpB,GAAG,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,EAC5C,IAAI,EAAE,KAAK,EACX,SAAS,EAAE,MAAM,CAAC,SAAS,EAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,GACnC,SAAS,CAwEX"}

View File

@@ -0,0 +1,219 @@
import { name as isIdentifierName } from 'estree-util-is-identifier-name';
import { createVisitors } from 'estree-util-scope';
import { walk } from 'estree-walker';
/**
* @param program
* The ESTree program to scan.
* @param file
* The {@link VFile} to emit warnings to.
* @param variables
* The variables that should be injected.
* @param options
* {@link define}.options
* @returns
* The position in the body where the export may be injected.
*/
function scan(program, file, variables, options) {
const visitors = createVisitors();
const [scope] = visitors.scopes;
const identifiers = new Map();
let injectIndex = 0;
walk(program, {
enter(node, parent) {
visitors.enter(node);
switch (node.type) {
case 'Identifier':
if (scope.defined.includes(node.name) && !identifiers.has(node.name)) {
identifiers.set(node.name, node);
}
break;
case 'ArrowFunctionExpression':
case 'ClassDeclaration':
case 'ClassExpression':
case 'FunctionExpression':
case 'FunctionDeclaration':
this.skip();
break;
// Dont insert before directives.
case 'ExpressionStatement':
if (parent === program &&
node.expression.type === 'Literal' &&
typeof node.expression.value === 'string') {
injectIndex = program.body.indexOf(node) + 1;
}
break;
default:
}
},
leave: visitors.exit
});
for (const name of scope.defined) {
if (variables.has(name)) {
if (options?.conflict !== 'skip') {
const identifier = identifiers.get(name);
const message = file.message(`Variable name conflict: ${name}`, {
place: identifier?.loc,
ruleId: 'conflict',
source: 'unist-util-mdx-define'
});
message.url = 'https://github.com/remcohaszing/unist-util-mdx-define';
if (options?.conflict !== 'warn') {
message.fatal = true;
throw message;
}
}
variables.delete(name);
}
}
return injectIndex;
}
/**
* Generate an export named declaration.
*
* @param variables
* The variables for which to generate an declaration.
* @param options
* {@link define} options
* @param returnStatement
* The return statement of the program to inject into.
* @returns
* The export named declaration.
*/
function generate(variables, options, returnStatement) {
if (options?.export === 'namespace') {
const statements = [];
for (const [name, right] of variables) {
const isIdentifier = isIdentifierName(name);
statements.push({
type: 'ExpressionStatement',
expression: {
type: 'AssignmentExpression',
left: {
type: 'MemberExpression',
computed: !isIdentifier,
object: { type: 'Identifier', name: 'MDXContent' },
optional: false,
property: isIdentifier ? { type: 'Identifier', name } : { type: 'Literal', value: name }
},
operator: '=',
right
}
});
}
return statements;
}
const declarations = [];
for (const [name, init] of variables) {
declarations.push({
type: 'VariableDeclaration',
kind: 'const',
declarations: [
{
type: 'VariableDeclarator',
id: { type: 'Identifier', name },
init
}
]
});
}
if (options?.export === false) {
return declarations;
}
if (!returnStatement) {
return declarations.map((declaration) => ({
type: 'ExportNamedDeclaration',
declaration,
specifiers: []
}));
}
if (returnStatement.argument?.type === 'ObjectExpression') {
returnStatement.argument.properties.splice(-1, 0, ...Array.from(variables.keys(), (name) => ({
type: 'Property',
computed: false,
kind: 'init',
method: false,
shorthand: true,
key: { type: 'Identifier', name },
value: { type: 'Identifier', name }
})));
}
return declarations;
}
/**
* Define variables in an MDX related AST.
*
* @param ast
* The AST in which to define an export
* @param file
* The {@link VFile} to emit warnings to.
* @param variables
* A mapping of variables to define. They keys are the names. The values are the ESTree expression
* to represent them.
* @param options
* Additional options to configure behaviour.
*/
export function define(ast, file, variables, options) {
const map = new Map(Object.entries(variables));
if (options?.export !== 'namespace') {
for (const name of map.keys()) {
if (name === '_createMdxContent' ||
name === '_Fragment' ||
name === '_jsx' ||
name === '_jsxs' ||
name === '_missingMdxReference' ||
name === 'MDXContent') {
const message = file.message(`MDX internal name conflict: ${name}`, {
ruleId: 'internal',
source: 'unist-util-mdx-define'
});
message.url = 'https://github.com/remcohaszing/unist-util-mdx-define';
message.fatal = true;
throw message;
}
if (!isIdentifierName(name)) {
const message = file.message(`Invalid identifier name: ${name}`, {
ruleId: 'invalid-identifier',
source: 'unist-util-mdx-define'
});
message.url = 'https://github.com/remcohaszing/unist-util-mdx-define';
message.fatal = true;
throw message;
}
}
}
if (ast.type === 'root') {
for (const child of ast.children) {
if (child.type !== 'mdxjsEsm') {
continue;
}
const program = child.data?.estree;
/* c8 ignore start */
if (!program) {
continue;
}
/* c8 ignore stop */
scan(program, file, map, options);
}
if (map.size) {
ast.children.unshift({
type: 'mdxjsEsm',
value: '',
data: {
estree: {
type: 'Program',
sourceType: 'module',
body: generate(map, options)
}
}
});
}
}
else {
const returnStatement = ast.body.find((node) => node.type === 'ReturnStatement');
const injectIndex = scan(ast, file, map, options);
if (map.size) {
ast.body.splice(injectIndex, 0, ...generate(map, options, returnStatement));
}
}
}
//# sourceMappingURL=unist-util-mdx-define.js.map

File diff suppressed because one or more lines are too long

51
node_modules/unist-util-mdx-define/package.json generated vendored Normal file
View File

@@ -0,0 +1,51 @@
{
"name": "unist-util-mdx-define",
"version": "1.1.2",
"description": "A unist utility to define MDX exports.",
"keywords": [],
"homepage": "https://github.com/remcohaszing/unist-util-mdx-define#readme",
"bugs": "https://github.com/remcohaszing/unist-util-mdx-define/issues",
"repository": "remcohaszing/unist-util-mdx-define",
"funding": "https://github.com/sponsors/remcohaszing",
"license": "MIT",
"author": "Remco Haszing <remcohaszing@gmail.com>",
"sideEffects": false,
"type": "module",
"exports": "./dist/unist-util-mdx-define.js",
"files": [
"dist",
"src",
"!*.test.*"
],
"scripts": {
"prepack": "tsc --build",
"pretest": "tsc --build",
"test": "node --test"
},
"dependencies": {
"@types/estree": "^1.0.0",
"@types/hast": "^3.0.0",
"@types/mdast": "^4.0.0",
"estree-util-is-identifier-name": "^3.0.0",
"estree-util-scope": "^1.0.0",
"estree-walker": "^3.0.0",
"vfile": "^6.0.0"
},
"devDependencies": {
"@mdx-js/mdx": "^3.0.0",
"acorn": "^8.0.0",
"astring": "^1.0.0",
"c8": "^9.0.0",
"eslint": "^8.0.0",
"eslint-config-remcohaszing": "^10.0.0",
"eslint-plugin-jsx-a11y": "^6.0.0",
"eslint-plugin-react": "^7.0.0",
"prettier": "^3.0.0",
"remark-cli": "^12.0.0",
"remark-preset-remcohaszing": "^3.0.0",
"snapshot-fixtures": "^1.0.0",
"typescript": "^5.0.0",
"unified": "^11.0.0",
"vfile-message": "^4.0.0"
}
}

View File

@@ -0,0 +1,308 @@
import type * as estree from 'estree'
import { name as isIdentifierName } from 'estree-util-is-identifier-name'
import { createVisitors } from 'estree-util-scope'
import { walk } from 'estree-walker'
import type * as hast from 'hast'
import type * as mdast from 'mdast'
import { type VFile } from 'vfile'
export namespace define {
/**
* A mapping of variables to define. They keys are the names. The values are the ESTree expression
* to represent them.
*/
export type Variables = Record<string, estree.Expression>
/**
* Options for {@link define}
*/
export interface Options {
/**
* If and how to export the variable.
*
* - `'module'`: Export the value using an ESM const export declaration.
* - `'namespace'`: Attach the value as a property on `MDXContent`.
* - `false`: Define the variable locally, but dont export it.
*
* @default 'module'
*/
export?: 'module' | 'namespace' | false | undefined
/**
* What to do if theres a name conflict.
*
* - `'skip'`: Dont insert the variable if theres a name conflict.
* - `'throw'`: Throw if theres a name conflict.
* - `'warn'`: Emit a vfile warning, but dont throw.
*
* @default 'throw'
*/
conflict?: 'skip' | 'throw' | 'warn' | undefined
}
}
/**
* @param program
* The ESTree program to scan.
* @param file
* The {@link VFile} to emit warnings to.
* @param variables
* The variables that should be injected.
* @param options
* {@link define}.options
* @returns
* The position in the body where the export may be injected.
*/
function scan(
program: estree.Program,
file: VFile,
variables: Map<string, estree.Expression>,
options: define.Options | undefined
): number {
const visitors = createVisitors()
const [scope] = visitors.scopes
const identifiers = new Map<string, estree.Identifier>()
let injectIndex = 0
walk(program, {
enter(node, parent) {
visitors.enter(node)
switch (node.type) {
case 'Identifier':
if (scope.defined.includes(node.name) && !identifiers.has(node.name)) {
identifiers.set(node.name, node)
}
break
case 'ArrowFunctionExpression':
case 'ClassDeclaration':
case 'ClassExpression':
case 'FunctionExpression':
case 'FunctionDeclaration':
this.skip()
break
// Dont insert before directives.
case 'ExpressionStatement':
if (
parent === program &&
node.expression.type === 'Literal' &&
typeof node.expression.value === 'string'
) {
injectIndex = program.body.indexOf(node) + 1
}
break
default:
}
},
leave: visitors.exit
})
for (const name of scope.defined) {
if (variables.has(name)) {
if (options?.conflict !== 'skip') {
const identifier = identifiers.get(name)
const message = file.message(`Variable name conflict: ${name}`, {
place: identifier?.loc,
ruleId: 'conflict',
source: 'unist-util-mdx-define'
})
message.url = 'https://github.com/remcohaszing/unist-util-mdx-define'
if (options?.conflict !== 'warn') {
message.fatal = true
throw message
}
}
variables.delete(name)
}
}
return injectIndex
}
/**
* Generate an export named declaration.
*
* @param variables
* The variables for which to generate an declaration.
* @param options
* {@link define} options
* @param returnStatement
* The return statement of the program to inject into.
* @returns
* The export named declaration.
*/
function generate(
variables: Map<string, estree.Expression>,
options: define.Options | undefined,
returnStatement?: estree.ReturnStatement | undefined
): (estree.ModuleDeclaration | estree.Statement)[] {
if (options?.export === 'namespace') {
const statements: estree.Statement[] = []
for (const [name, right] of variables) {
const isIdentifier = isIdentifierName(name)
statements.push({
type: 'ExpressionStatement',
expression: {
type: 'AssignmentExpression',
left: {
type: 'MemberExpression',
computed: !isIdentifier,
object: { type: 'Identifier', name: 'MDXContent' },
optional: false,
property: isIdentifier ? { type: 'Identifier', name } : { type: 'Literal', value: name }
},
operator: '=',
right
}
})
}
return statements
}
const declarations: estree.Declaration[] = []
for (const [name, init] of variables) {
declarations.push({
type: 'VariableDeclaration',
kind: 'const',
declarations: [
{
type: 'VariableDeclarator',
id: { type: 'Identifier', name },
init
}
]
})
}
if (options?.export === false) {
return declarations
}
if (!returnStatement) {
return declarations.map<estree.ExportNamedDeclaration>((declaration) => ({
type: 'ExportNamedDeclaration',
declaration,
specifiers: []
}))
}
if (returnStatement.argument?.type === 'ObjectExpression') {
returnStatement.argument.properties.splice(
-1,
0,
...Array.from(
variables.keys(),
(name): estree.Property => ({
type: 'Property',
computed: false,
kind: 'init',
method: false,
shorthand: true,
key: { type: 'Identifier', name },
value: { type: 'Identifier', name }
})
)
)
}
return declarations
}
/**
* Define variables in an MDX related AST.
*
* @param ast
* The AST in which to define an export
* @param file
* The {@link VFile} to emit warnings to.
* @param variables
* A mapping of variables to define. They keys are the names. The values are the ESTree expression
* to represent them.
* @param options
* Additional options to configure behaviour.
*/
export function define(
ast: estree.Program | hast.Root | mdast.Root,
file: VFile,
variables: define.Variables,
options?: define.Options | undefined
): undefined {
const map = new Map(Object.entries(variables))
if (options?.export !== 'namespace') {
for (const name of map.keys()) {
if (
name === '_createMdxContent' ||
name === '_Fragment' ||
name === '_jsx' ||
name === '_jsxs' ||
name === '_missingMdxReference' ||
name === 'MDXContent'
) {
const message = file.message(`MDX internal name conflict: ${name}`, {
ruleId: 'internal',
source: 'unist-util-mdx-define'
})
message.url = 'https://github.com/remcohaszing/unist-util-mdx-define'
message.fatal = true
throw message
}
if (!isIdentifierName(name)) {
const message = file.message(`Invalid identifier name: ${name}`, {
ruleId: 'invalid-identifier',
source: 'unist-util-mdx-define'
})
message.url = 'https://github.com/remcohaszing/unist-util-mdx-define'
message.fatal = true
throw message
}
}
}
if (ast.type === 'root') {
for (const child of ast.children) {
if (child.type !== 'mdxjsEsm') {
continue
}
const program = child.data?.estree
/* c8 ignore start */
if (!program) {
continue
}
/* c8 ignore stop */
scan(program, file, map, options)
}
if (map.size) {
ast.children.unshift({
type: 'mdxjsEsm',
value: '',
data: {
estree: {
type: 'Program',
sourceType: 'module',
body: generate(map, options)
}
}
})
}
} else {
const returnStatement = ast.body.find((node) => node.type === 'ReturnStatement')
const injectIndex = scan(ast, file, map, options)
if (map.size) {
ast.body.splice(injectIndex, 0, ...generate(map, options, returnStatement))
}
}
}