feat: complete MDX migration, stabilize routing and lead capture

Former-commit-id: ab5cc38c97e5f73d6e821465b90d199fb6e6edc9
This commit is contained in:
2026-05-03 21:06:47 +02:00
parent b13f628b55
commit f2fdea96ec
7175 changed files with 371649 additions and 1078689 deletions

View File

@@ -0,0 +1 @@
../../../@types+estree-jsx@1.0.5/node_modules/@types/estree-jsx

View File

@@ -0,0 +1 @@
../../acorn@8.16.0/node_modules/acorn

View File

@@ -0,0 +1 @@
../../esast-util-from-estree@2.0.0/node_modules/esast-util-from-estree

View File

@@ -0,0 +1,5 @@
export { fromJs } from "./lib/index.js";
export type Options = import('./lib/index.js').Options;
export type Version = import('./lib/index.js').Version;
export type Plugin = import('./lib/index.js').Plugin;
export type Value = import('./lib/index.js').Value;

View File

@@ -0,0 +1,8 @@
/**
* @typedef {import('./lib/index.js').Options} Options
* @typedef {import('./lib/index.js').Version} Version
* @typedef {import('./lib/index.js').Plugin} Plugin
* @typedef {import('./lib/index.js').Value} Value
*/
export {fromJs} from './lib/index.js'

View File

@@ -0,0 +1,96 @@
/**
* Parse JavaScript to an esast.
*
* @param {Value} value
* Serialized JavaScript to parse.
* @param {Options | null | undefined} [options]
* Configuration (optional).
* @returns {Program}
* Program node (as esast).
*/
export function fromJs(value: Value, options?: Options | null | undefined): Program;
export type ParserClass = typeof import('acorn').Parser;
export type Position = import('acorn').Position;
export type Comment = import('estree-jsx').Comment;
export type Program = import('estree-jsx').Program;
/**
* Input value
*
* When a typed array, must be UTF-8.
*/
export type Value = Uint8Array | string;
/**
* Extra fields in acorn errors.
*/
export type AcornErrorFields = {
/**
* Index.
*/
pos: number;
/**
* Acorn position.
*/
loc: Position;
};
/**
* Acorn error.
*/
export type AcornError = Error & AcornErrorFields;
/**
* Acorn plugin.
*/
export type Plugin = (Parser: ParserClass) => ParserClass;
/**
* JavaScript version.
*
* `'latest'` is equivalent to the latest supported year.
*/
export type Version = 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 'latest';
/**
* Configuration.
*/
export type Options = {
/**
* JavaScript version (year between 2015 and 2023 or `'latest'`,
* default: `'latest'`).
*
* When a number, must be a year in the range `2015` and `2023` (both
* including).
* `'latest'` is the same as passing the latest supported year.
*
* > ☢️ **Danger**: `'latest'` is a sliding thing, you could consider it as
* > breaking semver.
* > Pass an actual year to lock that down.
*/
version?: Version | null | undefined;
/**
* Whether this is a module (ESM) or a script (default: `false`).
*/
module?: boolean | null | undefined;
/**
* Whether a return statement is allowed in the top scope (default: `false`).
*/
allowReturnOutsideFunction?: boolean | null | undefined;
/**
* Whether import/export statements are allowed in the every scope (default:
* `false`).
*/
allowImportExportEverywhere?: boolean | null | undefined;
/**
* Whether `await` is allowed in the top scope (default: `version >= 2022`).
*/
allowAwaitOutsideFunction?: boolean | null | undefined;
/**
* Whether `super` is allowed outside methods (default: `false`).
*/
allowSuperOutsideMethod?: boolean | null | undefined;
/**
* Whether a shell hasbang is allowed (default: `false`).
*/
allowHashBang?: boolean | null | undefined;
/**
* List of acorn plugins (default: `[]`); examples are `acorn-jsx` and
* `acorn-stage3`.
*/
plugins?: Array<Plugin> | null | undefined;
};

View File

@@ -0,0 +1,138 @@
/**
* @typedef {typeof import('acorn').Parser} ParserClass
* @typedef {import('acorn').Position} Position
* @typedef {import('estree-jsx').Comment} Comment
* @typedef {import('estree-jsx').Program} Program
*/
/**
* @typedef {Uint8Array | string} Value
* Input value
*
* When a typed array, must be UTF-8.
*
* @typedef AcornErrorFields
* Extra fields in acorn errors.
* @property {number} pos
* Index.
* @property {Position} loc
* Acorn position.
*
* @typedef {Error & AcornErrorFields} AcornError
* Acorn error.
*
* @callback Plugin
* Acorn plugin.
* @param {ParserClass} Parser
* Base parser class.
* @returns {ParserClass}
* Resulting parser class.
*
* @typedef {2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 'latest'} Version
* JavaScript version.
*
* `'latest'` is equivalent to the latest supported year.
*
* @typedef Options
* Configuration.
* @property {Version | null | undefined} [version='latest']
* JavaScript version (year between 2015 and 2023 or `'latest'`,
* default: `'latest'`).
*
* When a number, must be a year in the range `2015` and `2023` (both
* including).
* `'latest'` is the same as passing the latest supported year.
*
* > ☢️ **Danger**: `'latest'` is a sliding thing, you could consider it as
* > breaking semver.
* > Pass an actual year to lock that down.
* @property {boolean | null | undefined} [module=false]
* Whether this is a module (ESM) or a script (default: `false`).
* @property {boolean | null | undefined} [allowReturnOutsideFunction=false]
* Whether a return statement is allowed in the top scope (default: `false`).
* @property {boolean | null | undefined} [allowImportExportEverywhere=false]
* Whether import/export statements are allowed in the every scope (default:
* `false`).
* @property {boolean | null | undefined} [allowAwaitOutsideFunction]
* Whether `await` is allowed in the top scope (default: `version >= 2022`).
* @property {boolean | null | undefined} [allowSuperOutsideMethod=false]
* Whether `super` is allowed outside methods (default: `false`).
* @property {boolean | null | undefined} [allowHashBang=false]
* Whether a shell hasbang is allowed (default: `false`).
* @property {Array<Plugin> | null | undefined} [plugins=[]]
* List of acorn plugins (default: `[]`); examples are `acorn-jsx` and
* `acorn-stage3`.
*/
import {Parser} from 'acorn'
import {fromEstree} from 'esast-util-from-estree'
import {VFileMessage} from 'vfile-message'
/**
* Parse JavaScript to an esast.
*
* @param {Value} value
* Serialized JavaScript to parse.
* @param {Options | null | undefined} [options]
* Configuration (optional).
* @returns {Program}
* Program node (as esast).
*/
export function fromJs(value, options) {
const options_ = options || {}
/** @type {ParserClass} */
let parser = Parser
/** @type {Array<Comment>} */
const comments = []
/** @type {Program} */
let tree
if (options_.plugins) {
parser = parser.extend(...options_.plugins)
}
const text =
typeof value === 'string'
? value.toString()
: new TextDecoder().decode(value)
try {
// @ts-expect-error: Acorn looks enough like estree.
tree = parser.parse(text, {
ecmaVersion: options_.version || 'latest',
sourceType: options_.module ? 'module' : 'script',
allowReturnOutsideFunction:
options_.allowReturnOutsideFunction || undefined,
allowImportExportEverywhere:
options_.allowImportExportEverywhere || undefined,
allowAwaitOutsideFunction:
options_.allowAwaitOutsideFunction || undefined,
allowHashBang: options_.allowHashBang || undefined,
allowSuperOutsideMethod: options_.allowSuperOutsideMethod || undefined,
locations: true,
// @ts-expect-error: Acorn looks enough like estree.
onComment: comments
})
} catch (error) {
const cause = /** @type {AcornError} */ (error)
const message = new VFileMessage('Could not parse JavaScript with Acorn', {
cause,
place: {
line: cause.loc.line,
column: cause.loc.column + 1,
offset: cause.pos
},
ruleId: 'acorn',
source: 'esast-util-from-js'
})
message.url = 'https://github.com/syntax-tree/esast-util-from-js#throws'
throw message
}
tree.comments = comments
return fromEstree(tree)
}

View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2022 Titus Wormer <tituswormer@gmail.com>
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.

View File

@@ -0,0 +1,21 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -z "$NODE_PATH" ]; then
export NODE_PATH="/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/bin/node_modules:/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/node_modules:/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/acorn@8.16.0/node_modules:/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/node_modules"
else
export NODE_PATH="/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/bin/node_modules:/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/acorn@8.16.0/node_modules/acorn/node_modules:/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/acorn@8.16.0/node_modules:/Volumes/Alpha SSD/Coding/e-tib.com/node_modules/.pnpm/node_modules:$NODE_PATH"
fi
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../../../../../acorn@8.16.0/node_modules/acorn/bin/acorn" "$@"
else
exec node "$basedir/../../../../../acorn@8.16.0/node_modules/acorn/bin/acorn" "$@"
fi

View File

@@ -0,0 +1,90 @@
{
"name": "esast-util-from-js",
"version": "2.0.1",
"description": "estree (and esast) utility to parse from JavaScript",
"license": "MIT",
"keywords": [
"unist",
"estree",
"estree-util",
"esast",
"esast-util",
"util",
"utility",
"js",
"parse",
"tokenize",
"acorn"
],
"repository": "syntax-tree/esast-util-from-js",
"bugs": "https://github.com/syntax-tree/esast-util-from-js/issues",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
},
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"contributors": [
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
],
"sideEffects": false,
"type": "module",
"exports": "./index.js",
"files": [
"lib/",
"index.d.ts",
"index.js"
],
"dependencies": {
"@types/estree-jsx": "^1.0.0",
"acorn": "^8.0.0",
"esast-util-from-estree": "^2.0.0",
"vfile-message": "^4.0.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"acorn-stage3": "^4.0.0",
"c8": "^8.0.0",
"prettier": "^3.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"xo": "^0.55.0"
},
"scripts": {
"prepack": "npm run build && npm run format",
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark . -qfo && prettier . -w --log-level warn && xo --fix",
"test-api": "node --conditions development test/index.js",
"test-coverage": "c8 --100 --reporter lcov npm run test-api",
"test": "npm run build && npm run format && npm run test-coverage"
},
"prettier": {
"bracketSpacing": false,
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
},
"remarkConfig": {
"plugins": [
"remark-preset-wooorm"
]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"ignoreCatch": true,
"strict": true
},
"xo": {
"ignore": [
"test/fixtures/"
],
"prettier": true,
"rules": {
"no-await-in-loop": "off"
}
}
}

View File

@@ -0,0 +1,338 @@
# esast-util-from-js
[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]
[![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
[esast][] (and [estree][]) utility to parse trees from JavaScript.
## Contents
* [What is this?](#what-is-this)
* [When should I use this?](#when-should-i-use-this)
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`fromJs(value[, options])`](#fromjsvalue-options)
* [`Options`](#options)
* [`Plugin`](#plugin)
* [`Value`](#value)
* [`Version`](#version-1)
* [Types](#types)
* [Compatibility](#compatibility)
* [Contribute](#contribute)
* [License](#license)
## What is this?
This package is a utility that turns a string of JavaScript into an esast
(estree with some extra cleanliness) syntax tree.
## When should I use this?
You can use this utility when you want to deal with ASTs of JavaScript
combined with other [unist][] and [`vfile`][vfile] things.
You can use [`acorn`][acorn] itself if you dont care about unified.
The utility [`estree-util-to-js`][estree-util-to-js] does the inverse of this
utility.
It turns the tree into a string of JavaScript.
## Install
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:
```sh
npm install esast-util-from-js
```
In Deno with [`esm.sh`][esmsh]:
```js
import {fromJs} from 'https://esm.sh/esast-util-from-js@2'
```
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import {fromJs} from 'https://esm.sh/esast-util-from-js@2?bundle'
</script>
```
## Use
```js
import fs from 'node:fs/promises'
import {fromJs} from 'esast-util-from-js'
const tree = fromJs(await fs.readFile('example.js'), {module: true})
console.log(tree)
```
Yields:
```js
{
type: 'Program',
body: [
{
type: 'ImportDeclaration',
specifiers: [Array],
source: [Object],
position: [Object]
},
{
type: 'ImportDeclaration',
specifiers: [Array],
source: [Object],
position: [Object]
},
{
type: 'VariableDeclaration',
declarations: [Array],
kind: 'const',
position: [Object]
},
{
type: 'ExpressionStatement',
expression: [Object],
position: [Object]
}
],
sourceType: 'module',
comments: [],
position: {
start: {line: 1, column: 1, offset: 0},
end: {line: 7, column: 1, offset: 157}
}
}
```
## API
This package exports the identifier [`fromJs`][api-from-js].
There is no default export.
### `fromJs(value[, options])`
Parse JavaScript to an esast.
###### Parameters
* `value` ([`Value`][api-value])
— serialized JavaScript to parse
* `options` ([`Options`][api-options], optional)
— configuration
###### Returns
Tree ([`Node`][node]).
###### Throws
When the JavaScript cannot be parsed with `acorn`, a
[`VFileMessage`][vfile-message] is thrown.
This can for example happen when passing modern syntax (you could maybe use a
newer `version`, or it might be that the syntax is not yet supported), or just
otherwise invalid JavaScript (you might need a plugin).
### `Options`
Configuration (TypeScript type).
##### Fields
###### `version`
JavaScript version ([`Version`][api-version], default: `'latest'`).
When a number, must be a year in the range `2015` and `2023` (both including).
`'latest'` is the same as passing the latest supported year.
> ☢️ **Danger**: `'latest'` is a sliding thing, you could consider it as
> breaking semver.
> Pass an actual year to lock that down.
###### `module`
Whether this is a module (ESM) or a script (`boolean`, default: `false`).
###### `allowReturnOutsideFunction`
Whether a return statement is allowed in the top scope (`boolean`, default:
`false`).
###### `allowImportExportEverywhere`
Whether import/export statements are allowed in the every scope (`boolean`,
default: `false`).
###### `allowAwaitOutsideFunction`
Whether `await` is allowed in the top scope (`boolean`, default: depends).
Defaults to `version >= 2022`.
###### `allowSuperOutsideMethod`
Whether `super` is allowed outside methods (`boolean`, default: `false`).
###### `allowHashBang`
Whether a shell hasbang is allowed (`boolean`, default: `false`).
###### `plugins`
List of acorn plugins ([`Array<Plugin>`][api-plugin], default: `[]`).
Examples are [`acorn-jsx`][acorn-jsx] and [`acorn-stage3`][acorn-stage3].
### `Plugin`
Acorn plugin (TypeScript type).
###### Type
```ts
type Plugin = (Parser: ParserClass) => ParserClass
```
### `Value`
Input value (TypeScript type).
When a typed array, must be UTF-8.
###### Type
```ts
type Value = Uint8Array | string
```
### `Version`
JavaScript version (TypeScript type).
`'latest'` is equivalent to the latest supported year.
###### Type
```ts
type Version = 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 'latest'
```
## Types
This package is fully typed with [TypeScript][].
It exports the additional types [`Options`][api-options],
[`Plugin`][api-plugin],
[`Value`][api-value], and
[`Version`][api-version].
## Compatibility
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line, `esast-util-from-js@^2`,
compatible with Node.js 16.
## Contribute
See [`contributing.md`][contributing] in [`syntax-tree/.github`][health] for
ways to get started.
See [`support.md`][support] for ways to get help.
This project has a [code of conduct][coc].
By interacting with this repository, organization, or community you agree to
abide by its terms.
## License
[MIT][license] © [Titus Wormer][author]
<!-- Definitions -->
[build-badge]: https://github.com/syntax-tree/esast-util-from-js/workflows/main/badge.svg
[build]: https://github.com/syntax-tree/esast-util-from-js/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/syntax-tree/esast-util-from-js.svg
[coverage]: https://codecov.io/github/syntax-tree/esast-util-from-js
[downloads-badge]: https://img.shields.io/npm/dm/esast-util-from-js.svg
[downloads]: https://www.npmjs.com/package/esast-util-from-js
[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=esast-util-from-js
[size]: https://bundlejs.com/?q=esast-util-from-js
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[collective]: https://opencollective.com/unified
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[chat]: https://github.com/syntax-tree/unist/discussions
[npm]: https://docs.npmjs.com/cli/install
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[typescript]: https://www.typescriptlang.org
[license]: license
[author]: https://wooorm.com
[health]: https://github.com/syntax-tree/.github
[contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md
[support]: https://github.com/syntax-tree/.github/blob/main/support.md
[coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md
[esast]: https://github.com/syntax-tree/esast
[node]: https://github.com/syntax-tree/esast#node
[estree]: https://github.com/estree/estree
[unist]: https://github.com/syntax-tree/unist
[vfile]: https://github.com/vfile/vfile
[acorn]: https://github.com/acornjs/acorn
[acorn-jsx]: https://github.com/acornjs/acorn-jsx
[acorn-stage3]: https://github.com/acornjs/acorn-stage3
[estree-util-to-js]: https://github.com/syntax-tree/estree-util-to-js
[vfile-message]: https://github.com/vfile/vfile-message
[api-from-js]: #fromjsvalue-options
[api-options]: #options
[api-plugin]: #plugin
[api-value]: #value
[api-version]: #version-1

View File

@@ -0,0 +1 @@
../../vfile-message@4.0.3/node_modules/vfile-message