mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(ast_tools): output typescript to a separate package (#6755)
Part of #6347. Moves typescript logic from derive_estree into a new ast_tools generator.
This commit is contained in:
parent
1c27a2c36c
commit
1145341a92
30 changed files with 2406 additions and 1071 deletions
1
.github/.generated_ast_watch_list.yml
vendored
1
.github/.generated_ast_watch_list.yml
vendored
|
|
@ -32,5 +32,6 @@ src:
|
|||
- 'crates/oxc_ast/src/generated/ast_builder.rs'
|
||||
- 'crates/oxc_ast/src/generated/visit.rs'
|
||||
- 'crates/oxc_ast/src/generated/visit_mut.rs'
|
||||
- 'npm/oxc-types/src/generated/types.d.ts'
|
||||
- 'tasks/ast_tools/src/**'
|
||||
- '.github/.generated_ast_watch_list.yml'
|
||||
|
|
|
|||
28
.github/workflows/ci.yml
vendored
28
.github/workflows/ci.yml
vendored
|
|
@ -125,18 +125,20 @@ jobs:
|
|||
with:
|
||||
cache-key: wasm
|
||||
save-cache: ${{ github.ref_name == 'main' }}
|
||||
tools: wasm-pack
|
||||
tools: wasm-pack,just
|
||||
- name: Check
|
||||
run: |
|
||||
rustup target add wasm32-unknown-unknown
|
||||
cargo check -p oxc_wasm --target wasm32-unknown-unknown
|
||||
- uses: ./.github/actions/pnpm
|
||||
- name: Build
|
||||
run: |
|
||||
wasm-pack build --target web --dev ./crates/oxc_wasm
|
||||
wasm-pack build --target web --dev ./wasm/parser
|
||||
- uses: ./.github/actions/pnpm
|
||||
just build-wasm debug
|
||||
cd ./wasm/parser && pnpm build
|
||||
- name: Check output types
|
||||
run: npx -y -p typescript tsc --lib es2020,dom crates/oxc_wasm/pkg/oxc_wasm.d.ts
|
||||
run: |
|
||||
pnpm install
|
||||
npx -y -p typescript tsc --lib es2020,dom npm/oxc-wasm/oxc_wasm.d.ts
|
||||
|
||||
typos:
|
||||
name: Spell Check
|
||||
|
|
@ -262,9 +264,17 @@ jobs:
|
|||
if: steps.filter.outputs.src == 'true'
|
||||
with:
|
||||
components: rustfmt
|
||||
tools: dprint
|
||||
cache-key: ast_changes
|
||||
save-cache: ${{ github.ref_name == 'main' }}
|
||||
|
||||
- name: Restore dprint plugin cache
|
||||
id: cache-restore
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
key: dprint-autofix-ci-${{ runner.os }}-${{ hashFiles('dprint.json') }}
|
||||
path: ~/.cache/dprint
|
||||
|
||||
- name: Check AST Changes
|
||||
if: steps.filter.outputs.src == 'true'
|
||||
run: |
|
||||
|
|
@ -272,6 +282,14 @@ jobs:
|
|||
git diff --exit-code ||
|
||||
(echo 'AST changes caused the "generated" code to get outdated. Have you forgotten to run the `just ast` command and/or commit generated codes?' && exit 1)
|
||||
|
||||
- name: Save dprint plugin cache
|
||||
if: ${{ github.ref_name == 'main' }}
|
||||
id: cache-save
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
|
||||
path: ~/.cache/dprint
|
||||
|
||||
napi:
|
||||
name: Test NAPI
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
54
.github/workflows/release_types.yml
vendored
Normal file
54
.github/workflows/release_types.yml
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
name: Release @oxc/types
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- npm/oxc-types/package.json # Please only commit this file, so we don't need to wait for all the other CI jobs to finish.
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check version
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
version_changed: ${{ steps.version.outputs.changed }}
|
||||
steps:
|
||||
- uses: taiki-e/checkout-action@v1
|
||||
|
||||
- name: Check version changes
|
||||
uses: EndBug/version-check@v2
|
||||
id: version
|
||||
with:
|
||||
static-checking: localIsNew
|
||||
file-url: https://unpkg.com/@oxc/types/package.json
|
||||
file-name: npm/oxc-types/package.json
|
||||
|
||||
- name: Set version name
|
||||
if: steps.version.outputs.changed == 'true'
|
||||
run: |
|
||||
echo "Version change found! New version: ${{ steps.version.outputs.version }} (${{ steps.version.outputs.version_type }})"
|
||||
|
||||
build:
|
||||
needs: check
|
||||
if: needs.check.outputs.version_changed == 'true'
|
||||
name: Release @oxc/types
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # for `pnpm publish --provenance`
|
||||
steps:
|
||||
- uses: taiki-e/checkout-action@v1
|
||||
|
||||
- uses: ./.github/actions/pnpm
|
||||
|
||||
- name: Publish
|
||||
working-directory: npm/oxc-types
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
run: pnpm publish --provenance --access public
|
||||
3
Cargo.lock
generated
3
Cargo.lock
generated
|
|
@ -1453,7 +1453,6 @@ dependencies = [
|
|||
"oxc_syntax",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1865,7 +1864,6 @@ dependencies = [
|
|||
"rustc-hash",
|
||||
"serde",
|
||||
"unicode-id-start",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1937,7 +1935,6 @@ dependencies = [
|
|||
"oxc_estree",
|
||||
"schemars",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -31,14 +31,12 @@ num-bigint = { workspace = true }
|
|||
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
wasm-bindgen = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serialize = [
|
||||
"dep:serde",
|
||||
"dep:serde_json",
|
||||
"dep:wasm-bindgen",
|
||||
"oxc_allocator/serialize",
|
||||
"oxc_regular_expression/serialize",
|
||||
"oxc_span/serialize",
|
||||
|
|
|
|||
|
|
@ -190,26 +190,3 @@ bitflags! {
|
|||
const V = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = r#"
|
||||
export type RegExpFlags = {
|
||||
/** Global flag */
|
||||
G: 1,
|
||||
/** Ignore case flag */
|
||||
I: 2,
|
||||
/** Multiline flag */
|
||||
M: 4,
|
||||
/** DotAll flag */
|
||||
S: 8,
|
||||
/** Unicode flag */
|
||||
U: 16,
|
||||
/** Sticky flag */
|
||||
Y: 32,
|
||||
/** Indices flag */
|
||||
D: 64,
|
||||
/** Unicode sets flag */
|
||||
V: 128
|
||||
};
|
||||
"#;
|
||||
|
|
|
|||
32
crates/oxc_ast/src/ast/types.d.ts
vendored
Normal file
32
crates/oxc_ast/src/ast/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
export interface FormalParameterRest extends Span {
|
||||
type: 'RestElement';
|
||||
argument: BindingPatternKind;
|
||||
typeAnnotation: TSTypeAnnotation | null;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
export type RegExpFlags = {
|
||||
/** Global flag */
|
||||
G: 1;
|
||||
/** Ignore case flag */
|
||||
I: 2;
|
||||
/** Multiline flag */
|
||||
M: 4;
|
||||
/** DotAll flag */
|
||||
S: 8;
|
||||
/** Unicode flag */
|
||||
U: 16;
|
||||
/** Sticky flag */
|
||||
Y: 32;
|
||||
/** Indices flag */
|
||||
D: 64;
|
||||
/** Unicode sets flag */
|
||||
V: 128;
|
||||
};
|
||||
|
||||
export type JSXElementName =
|
||||
| JSXIdentifier
|
||||
| JSXNamespacedName
|
||||
| JSXMemberExpression;
|
||||
|
||||
export type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression;
|
||||
|
|
@ -5,13 +5,6 @@ use oxc_span::Atom;
|
|||
|
||||
use crate::ast::*;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = r#"
|
||||
export type JSXElementName = JSXIdentifier | JSXNamespacedName | JSXMemberExpression;
|
||||
export type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression;
|
||||
"#;
|
||||
|
||||
// 1.2 JSX Elements
|
||||
|
||||
impl<'a> fmt::Display for JSXIdentifier<'a> {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -156,17 +156,6 @@ impl<'a> Serialize for FormalParameters<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = r#"
|
||||
export type FormalParameterRest = ({
|
||||
type: "RestElement",
|
||||
argument: BindingPatternKind,
|
||||
typeAnnotation: TSTypeAnnotation | null,
|
||||
optional: boolean,
|
||||
}) & Span;
|
||||
"#;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type", rename = "FormalParameters")]
|
||||
struct SerFormalParameters<'a, 'b> {
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ rustc-hash = { workspace = true }
|
|||
unicode-id-start = { workspace = true }
|
||||
|
||||
serde = { workspace = true, optional = true }
|
||||
wasm-bindgen = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serialize = ["dep:serde", "dep:wasm-bindgen", "oxc_allocator/serialize", "oxc_span/serialize"]
|
||||
serialize = ["dep:serde", "oxc_allocator/serialize", "oxc_span/serialize"]
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ impl<'a> Serialize for Pattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type Pattern = ({\n\ttype: 'Pattern';\n\tbody: Disjunction;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for Disjunction<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -32,10 +28,6 @@ impl<'a> Serialize for Disjunction<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type Disjunction = ({\n\ttype: 'Disjunction';\n\tbody: Array<Alternative>;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for Alternative<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -46,10 +38,6 @@ impl<'a> Serialize for Alternative<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type Alternative = ({\n\ttype: 'Alternative';\n\tbody: Array<Term>;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for Term<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
|
|
@ -69,9 +57,6 @@ impl<'a> Serialize for Term<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type Term = BoundaryAssertion | LookAroundAssertion | Quantifier | Character | Dot | CharacterClassEscape | UnicodePropertyEscape | CharacterClass | CapturingGroup | IgnoreGroup | IndexedReference | NamedReference;";
|
||||
|
||||
impl Serialize for BoundaryAssertion {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -82,9 +67,6 @@ impl Serialize for BoundaryAssertion {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type BoundaryAssertion = ({\n\ttype: 'BoundaryAssertion';\n\tspan: Span;\n\tkind: BoundaryAssertionKind;\n});";
|
||||
|
||||
impl Serialize for BoundaryAssertionKind {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -104,10 +86,6 @@ impl Serialize for BoundaryAssertionKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type BoundaryAssertionKind = 'start' | 'end' | 'boundary' | 'negativeBoundary';";
|
||||
|
||||
impl<'a> Serialize for LookAroundAssertion<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -119,9 +97,6 @@ impl<'a> Serialize for LookAroundAssertion<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type LookAroundAssertion = ({\n\ttype: 'LookAroundAssertion';\n\tkind: LookAroundAssertionKind;\n\tbody: Disjunction;\n}) & Span;";
|
||||
|
||||
impl Serialize for LookAroundAssertionKind {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -145,9 +120,6 @@ impl Serialize for LookAroundAssertionKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type LookAroundAssertionKind = 'lookahead' | 'negativeLookahead' | 'lookbehind' | 'negativeLookbehind';";
|
||||
|
||||
impl<'a> Serialize for Quantifier<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -161,9 +133,6 @@ impl<'a> Serialize for Quantifier<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type Quantifier = ({\n\ttype: 'Quantifier';\n\tmin: number;\n\tmax: (number) | null;\n\tgreedy: boolean;\n\tbody: Term;\n}) & Span;";
|
||||
|
||||
impl Serialize for Character {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -175,9 +144,6 @@ impl Serialize for Character {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type Character = ({\n\ttype: 'Character';\n\tkind: CharacterKind;\n\tvalue: number;\n}) & Span;";
|
||||
|
||||
impl Serialize for CharacterKind {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -213,9 +179,6 @@ impl Serialize for CharacterKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CharacterKind = 'controlLetter' | 'hexadecimalEscape' | 'identifier' | 'null' | 'octal1' | 'octal2' | 'octal3' | 'singleEscape' | 'symbol' | 'unicodeEscape';";
|
||||
|
||||
impl Serialize for CharacterClassEscape {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -226,9 +189,6 @@ impl Serialize for CharacterClassEscape {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CharacterClassEscape = ({\n\ttype: 'CharacterClassEscape';\n\tkind: CharacterClassEscapeKind;\n}) & Span;";
|
||||
|
||||
impl Serialize for CharacterClassEscapeKind {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -254,9 +214,6 @@ impl Serialize for CharacterClassEscapeKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CharacterClassEscapeKind = 'd' | 'negativeD' | 's' | 'negativeS' | 'w' | 'negativeW';";
|
||||
|
||||
impl<'a> Serialize for UnicodePropertyEscape<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -270,9 +227,6 @@ impl<'a> Serialize for UnicodePropertyEscape<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type UnicodePropertyEscape = ({\n\ttype: 'UnicodePropertyEscape';\n\tnegative: boolean;\n\tstrings: boolean;\n\tname: string;\n\tvalue: (string) | null;\n}) & Span;";
|
||||
|
||||
impl Serialize for Dot {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -282,9 +236,6 @@ impl Serialize for Dot {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type Dot = ({\n\ttype: 'Dot';\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for CharacterClass<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -298,9 +249,6 @@ impl<'a> Serialize for CharacterClass<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CharacterClass = ({\n\ttype: 'CharacterClass';\n\tnegative: boolean;\n\tstrings: boolean;\n\tkind: CharacterClassContentsKind;\n\tbody: Array<CharacterClassContents>;\n}) & Span;";
|
||||
|
||||
impl Serialize for CharacterClassContentsKind {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -319,10 +267,6 @@ impl Serialize for CharacterClassContentsKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type CharacterClassContentsKind = 'union' | 'intersection' | 'subtraction';";
|
||||
|
||||
impl<'a> Serialize for CharacterClassContents<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
|
|
@ -338,9 +282,6 @@ impl<'a> Serialize for CharacterClassContents<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CharacterClassContents = CharacterClassRange | CharacterClassEscape | UnicodePropertyEscape | Character | CharacterClass | ClassStringDisjunction;";
|
||||
|
||||
impl Serialize for CharacterClassRange {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -352,9 +293,6 @@ impl Serialize for CharacterClassRange {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CharacterClassRange = ({\n\ttype: 'CharacterClassRange';\n\tmin: Character;\n\tmax: Character;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for ClassStringDisjunction<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -366,9 +304,6 @@ impl<'a> Serialize for ClassStringDisjunction<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type ClassStringDisjunction = ({\n\ttype: 'ClassStringDisjunction';\n\tstrings: boolean;\n\tbody: Array<ClassString>;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for ClassString<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -380,9 +315,6 @@ impl<'a> Serialize for ClassString<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type ClassString = ({\n\ttype: 'ClassString';\n\tstrings: boolean;\n\tbody: Array<Character>;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for CapturingGroup<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -394,9 +326,6 @@ impl<'a> Serialize for CapturingGroup<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type CapturingGroup = ({\n\ttype: 'CapturingGroup';\n\tname: (string) | null;\n\tbody: Disjunction;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for IgnoreGroup<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -408,9 +337,6 @@ impl<'a> Serialize for IgnoreGroup<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type IgnoreGroup = ({\n\ttype: 'IgnoreGroup';\n\tmodifiers: (Modifiers) | null;\n\tbody: Disjunction;\n}) & Span;";
|
||||
|
||||
impl Serialize for Modifiers {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -422,9 +348,6 @@ impl Serialize for Modifiers {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type Modifiers = ({\n\ttype: 'Modifiers';\n\tenabling: (Modifier) | null;\n\tdisabling: (Modifier) | null;\n}) & Span;";
|
||||
|
||||
impl Serialize for Modifier {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -436,9 +359,6 @@ impl Serialize for Modifier {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type Modifier = ({\n\ttype: 'Modifier';\n\tignoreCase: boolean;\n\tmultiline: boolean;\n\tsticky: boolean;\n});";
|
||||
|
||||
impl Serialize for IndexedReference {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -449,10 +369,6 @@ impl Serialize for IndexedReference {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type IndexedReference = ({\n\ttype: 'IndexedReference';\n\tindex: number;\n}) & Span;";
|
||||
|
||||
impl<'a> Serialize for NamedReference<'a> {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -462,7 +378,3 @@ impl<'a> Serialize for NamedReference<'a> {
|
|||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type NamedReference = ({\n\ttype: 'NamedReference';\n\tname: string;\n}) & Span;";
|
||||
|
|
|
|||
|
|
@ -29,9 +29,8 @@ miette = { workspace = true }
|
|||
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true, features = ["derive"], optional = true }
|
||||
wasm-bindgen = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serialize = ["compact_str/serde", "dep:serde", "dep:wasm-bindgen"]
|
||||
serialize = ["compact_str/serde", "dep:serde"]
|
||||
schemars = ["dep:schemars"]
|
||||
|
|
|
|||
|
|
@ -20,10 +20,6 @@ impl Serialize for Span {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type Span = ({\n\tstart: number;\n\tend: number;\n});";
|
||||
|
||||
impl Serialize for SourceType {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(None)?;
|
||||
|
|
@ -34,9 +30,6 @@ impl Serialize for SourceType {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type SourceType = ({\n\tlanguage: Language;\n\tmoduleKind: ModuleKind;\n\tvariant: LanguageVariant;\n});";
|
||||
|
||||
impl Serialize for Language {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -53,10 +46,6 @@ impl Serialize for Language {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type Language = 'javascript' | 'typescript' | 'typescriptDefinition';";
|
||||
|
||||
impl Serialize for ModuleKind {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -69,10 +58,6 @@ impl Serialize for ModuleKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type ModuleKind = 'script' | 'module' | 'unambiguous';";
|
||||
|
||||
impl Serialize for LanguageVariant {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -85,6 +70,3 @@ impl Serialize for LanguageVariant {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type LanguageVariant = 'standard' | 'jsx';";
|
||||
|
|
|
|||
|
|
@ -63,9 +63,6 @@ impl Serialize for AssignmentOperator {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type AssignmentOperator = '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '<<=' | '>>=' | '>>>=' | '|=' | '^=' | '&=' | '&&=' | '||=' | '??=' | '**=';";
|
||||
|
||||
impl Serialize for BinaryOperator {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -137,9 +134,6 @@ impl Serialize for BinaryOperator {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type BinaryOperator = '==' | '!=' | '===' | '!==' | '<' | '<=' | '>' | '>=' | '<<' | '>>' | '>>>' | '+' | '-' | '*' | '/' | '%' | '|' | '^' | '&' | 'in' | 'instanceof' | '**';";
|
||||
|
||||
impl Serialize for LogicalOperator {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -154,9 +148,6 @@ impl Serialize for LogicalOperator {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type LogicalOperator = '||' | '&&' | '??';";
|
||||
|
||||
impl Serialize for UnaryOperator {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -183,10 +174,6 @@ impl Serialize for UnaryOperator {
|
|||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str =
|
||||
"export type UnaryOperator = '-' | '+' | '!' | '~' | 'typeof' | 'void' | 'delete';";
|
||||
|
||||
impl Serialize for UpdateOperator {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match *self {
|
||||
|
|
@ -199,6 +186,3 @@ impl Serialize for UpdateOperator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = "export type UpdateOperator = '++' | '--';";
|
||||
|
|
|
|||
30
crates/oxc_wasm/package.json
Normal file
30
crates/oxc_wasm/package.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "oxc_wasm",
|
||||
"type": "module",
|
||||
"collaborators": [
|
||||
"Boshen <boshenc@gmail.com>",
|
||||
"Oxc contributors"
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"oxc_wasm_bg.wasm",
|
||||
"oxc_wasm.js",
|
||||
"oxc_wasm.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@oxc/types": "workspace:^"
|
||||
},
|
||||
"main": "oxc_wasm.js",
|
||||
"types": "oxc_wasm.d.ts",
|
||||
"sideEffects": [
|
||||
"./snippets/*"
|
||||
],
|
||||
"keywords": [
|
||||
"JavaScript",
|
||||
"TypeScript",
|
||||
"linter",
|
||||
"minifier",
|
||||
"parser"
|
||||
]
|
||||
}
|
||||
|
|
@ -32,6 +32,12 @@ use wasm_bindgen::prelude::*;
|
|||
|
||||
use crate::options::{OxcOptions, OxcRunOptions};
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = r#"
|
||||
import type { Program, Span } from "@oxc/types";
|
||||
export * from "@oxc/types";
|
||||
"#;
|
||||
|
||||
#[wasm_bindgen(getter_with_clone)]
|
||||
#[derive(Default, Tsify)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
|
|||
1
justfile
1
justfile
|
|
@ -136,6 +136,7 @@ watch-wasm:
|
|||
|
||||
build-wasm mode="release":
|
||||
wasm-pack build --out-dir ../../npm/oxc-wasm --target web --{{mode}} --scope oxc crates/oxc_wasm
|
||||
cp crates/oxc_wasm/package.json npm/oxc-wasm/package.json
|
||||
|
||||
# Generate the JavaScript global variables. See `tasks/javascript_globals`
|
||||
javascript-globals:
|
||||
|
|
|
|||
3
npm/oxc-types/README.md
Normal file
3
npm/oxc-types/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Oxc Types
|
||||
|
||||
Typescript definitions for Oxc AST nodes.
|
||||
27
npm/oxc-types/package.json
Normal file
27
npm/oxc-types/package.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@oxc/types",
|
||||
"version": "0.32.0",
|
||||
"description": "Types for Oxc AST nodes",
|
||||
"keywords": [
|
||||
"AST",
|
||||
"Parser"
|
||||
],
|
||||
"author": "Boshen and oxc contributors",
|
||||
"license": "MIT",
|
||||
"homepage": "https://oxc.rs",
|
||||
"bugs": "https://github.com/oxc-project/oxc/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/oxc-project/oxc.git",
|
||||
"directory": "npm/oxc-types"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
},
|
||||
"main": "",
|
||||
"types": "src/index.d.ts",
|
||||
"files": [
|
||||
"src/index.d.ts",
|
||||
"src/generated/types.d.ts"
|
||||
]
|
||||
}
|
||||
2010
npm/oxc-types/src/generated/types.d.ts
vendored
Normal file
2010
npm/oxc-types/src/generated/types.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
npm/oxc-types/src/index.d.ts
vendored
Normal file
1
npm/oxc-types/src/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './generated/types';
|
||||
|
|
@ -58,6 +58,26 @@ importers:
|
|||
|
||||
napi/transform: {}
|
||||
|
||||
npm/oxc-parser: {}
|
||||
|
||||
npm/oxc-transform: {}
|
||||
|
||||
npm/oxc-types: {}
|
||||
|
||||
npm/oxc-wasm:
|
||||
devDependencies:
|
||||
'@oxc/types':
|
||||
specifier: workspace:^
|
||||
version: link:../oxc-types
|
||||
|
||||
npm/oxlint: {}
|
||||
|
||||
npm/parser-wasm:
|
||||
devDependencies:
|
||||
'@oxc/types':
|
||||
specifier: workspace:^
|
||||
version: link:../oxc-types
|
||||
|
||||
tasks/benchmark/codspeed:
|
||||
devDependencies:
|
||||
axios:
|
||||
|
|
@ -70,7 +90,13 @@ importers:
|
|||
specifier: ^7.2.0
|
||||
version: 7.4.3
|
||||
|
||||
wasm/parser: {}
|
||||
wasm/parser:
|
||||
devDependencies:
|
||||
'@oxc/types':
|
||||
specifier: workspace:^
|
||||
version: link:../../npm/oxc-types
|
||||
|
||||
wasm/parser/pkg: {}
|
||||
|
||||
packages:
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ packages:
|
|||
- 'wasm/**'
|
||||
- 'editors/**'
|
||||
- 'tasks/benchmark/codspeed'
|
||||
- 'npm/**'
|
||||
|
||||
catalog:
|
||||
"@napi-rs/cli": 3.0.0-alpha.61
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use convert_case::{Case, Casing};
|
||||
use itertools::Itertools;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
|
|
@ -9,7 +8,7 @@ use crate::{
|
|||
markers::ESTreeStructAttribute,
|
||||
schema::{
|
||||
serialize::{enum_variant_name, get_type_tag},
|
||||
EnumDef, GetGenerics, GetIdent, StructDef, TypeDef, TypeName,
|
||||
EnumDef, GetGenerics, GetIdent, StructDef, TypeDef,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -27,19 +26,6 @@ impl Derive for DeriveESTree {
|
|||
}
|
||||
|
||||
fn derive(&mut self, def: &TypeDef, _: &LateCtx) -> TokenStream {
|
||||
let ts_type_def = match def {
|
||||
TypeDef::Enum(def) => typescript_enum(def),
|
||||
TypeDef::Struct(def) => Some(typescript_struct(def)),
|
||||
};
|
||||
let ts_type_def = if let Some(ts_type_def) = ts_type_def {
|
||||
quote! {
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = #ts_type_def;
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
if let TypeDef::Struct(def) = def {
|
||||
if def
|
||||
.markers
|
||||
|
|
@ -47,7 +33,7 @@ impl Derive for DeriveESTree {
|
|||
.as_ref()
|
||||
.is_some_and(|e| e == &ESTreeStructAttribute::CustomSerialize)
|
||||
{
|
||||
return ts_type_def;
|
||||
return TokenStream::new();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,9 +50,6 @@ impl Derive for DeriveESTree {
|
|||
#body
|
||||
}
|
||||
}
|
||||
|
||||
///@@line_break
|
||||
#ts_type_def
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,72 +154,3 @@ fn serialize_enum(def: &EnumDef) -> TokenStream {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Untagged enums: "type Expression = BooleanLiteral | NullLiteral"
|
||||
// Tagged enums: "type PropertyKind = 'init' | 'get' | 'set'"
|
||||
fn typescript_enum(def: &EnumDef) -> Option<String> {
|
||||
if def.markers.estree.custom_ts_def {
|
||||
return None;
|
||||
}
|
||||
|
||||
let union = if def.markers.estree.untagged {
|
||||
def.all_variants().map(|var| type_to_string(var.fields[0].typ.name())).join(" | ")
|
||||
} else {
|
||||
def.all_variants().map(|var| format!("'{}'", enum_variant_name(var, def))).join(" | ")
|
||||
};
|
||||
let ident = def.ident();
|
||||
Some(format!("export type {ident} = {union};"))
|
||||
}
|
||||
|
||||
fn typescript_struct(def: &StructDef) -> String {
|
||||
let ident = def.ident();
|
||||
let mut fields = String::new();
|
||||
let mut extends = vec![];
|
||||
|
||||
if let Some(type_tag) = get_type_tag(def) {
|
||||
fields.push_str(&format!("\n\ttype: '{type_tag}';"));
|
||||
}
|
||||
|
||||
for field in &def.fields {
|
||||
if field.markers.derive_attributes.estree.skip {
|
||||
continue;
|
||||
}
|
||||
let ty = match &field.markers.derive_attributes.tsify_type {
|
||||
Some(ty) => ty.clone(),
|
||||
None => type_to_string(field.typ.name()),
|
||||
};
|
||||
|
||||
if field.markers.derive_attributes.estree.flatten {
|
||||
extends.push(ty);
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = match &field.markers.derive_attributes.estree.rename {
|
||||
Some(rename) => rename.to_string(),
|
||||
None => field.name.clone().unwrap().to_case(Case::Camel),
|
||||
};
|
||||
|
||||
fields.push_str(&format!("\n\t{name}: {ty};"));
|
||||
}
|
||||
let extends =
|
||||
if extends.is_empty() { String::new() } else { format!(" & {}", extends.join(" & ")) };
|
||||
format!("export type {ident} = ({{{fields}\n}}){extends};")
|
||||
}
|
||||
|
||||
fn type_to_string(ty: &TypeName) -> String {
|
||||
match ty {
|
||||
TypeName::Ident(ident) => match ident.as_str() {
|
||||
"f64" | "f32" | "usize" | "u64" | "u32" | "u16" | "u8" | "i64" | "i32" | "i16"
|
||||
| "i8" => "number",
|
||||
"bool" => "boolean",
|
||||
"str" | "String" | "Atom" | "CompactStr" => "string",
|
||||
ty => ty,
|
||||
}
|
||||
.to_string(),
|
||||
TypeName::Vec(type_name) => format!("Array<{}>", type_to_string(type_name)),
|
||||
TypeName::Box(type_name) | TypeName::Ref(type_name) | TypeName::Complex(type_name) => {
|
||||
type_to_string(type_name)
|
||||
}
|
||||
TypeName::Opt(type_name) => format!("({}) | null", type_to_string(type_name)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ use crate::codegen::LateCtx;
|
|||
mod assert_layouts;
|
||||
mod ast_builder;
|
||||
mod ast_kind;
|
||||
mod typescript;
|
||||
mod visit;
|
||||
|
||||
pub use assert_layouts::AssertLayouts;
|
||||
pub use ast_builder::AstBuilderGenerator;
|
||||
pub use ast_kind::AstKindGenerator;
|
||||
pub use typescript::TypescriptGenerator;
|
||||
pub use visit::{VisitGenerator, VisitMutGenerator};
|
||||
|
||||
/// Inserts a newline in the `TokenStream`.
|
||||
|
|
@ -28,15 +30,8 @@ pub trait Generator {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum GeneratorOutput {
|
||||
Rust {
|
||||
path: PathBuf,
|
||||
tokens: TokenStream,
|
||||
},
|
||||
#[expect(dead_code)]
|
||||
Text {
|
||||
path: PathBuf,
|
||||
content: String,
|
||||
},
|
||||
Rust { path: PathBuf, tokens: TokenStream },
|
||||
Text { path: PathBuf, content: String },
|
||||
}
|
||||
|
||||
macro_rules! define_generator {
|
||||
|
|
|
|||
170
tasks/ast_tools/src/generators/typescript.rs
Normal file
170
tasks/ast_tools/src/generators/typescript.rs
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
use convert_case::{Case, Casing};
|
||||
use itertools::Itertools;
|
||||
use std::{
|
||||
io::Write,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use super::define_generator;
|
||||
use crate::{
|
||||
codegen::LateCtx,
|
||||
output,
|
||||
schema::{
|
||||
serialize::{enum_variant_name, get_type_tag},
|
||||
EnumDef, GetIdent, StructDef, TypeDef, TypeName,
|
||||
},
|
||||
Generator, GeneratorOutput,
|
||||
};
|
||||
|
||||
const CUSTOM_TYPESCRIPT: &str = include_str!("../../../../crates/oxc_ast/src/ast/types.d.ts");
|
||||
|
||||
define_generator! {
|
||||
pub struct TypescriptGenerator;
|
||||
}
|
||||
|
||||
impl Generator for TypescriptGenerator {
|
||||
fn generate(&mut self, ctx: &LateCtx) -> GeneratorOutput {
|
||||
let file = file!().replace('\\', "/");
|
||||
let mut content = format!(
|
||||
"\
|
||||
// To edit this generated file you have to edit `{file}`\n\
|
||||
// Auto-generated code, DO NOT EDIT DIRECTLY!\n\n\
|
||||
{CUSTOM_TYPESCRIPT}\n\
|
||||
"
|
||||
);
|
||||
|
||||
for def in ctx.schema() {
|
||||
if !def.generates_derive("ESTree") {
|
||||
continue;
|
||||
}
|
||||
let ts_type_def = match def {
|
||||
TypeDef::Struct(it) => Some(typescript_struct(it)),
|
||||
TypeDef::Enum(it) => typescript_enum(it),
|
||||
};
|
||||
let Some(ts_type_def) = ts_type_def else { continue };
|
||||
|
||||
content.push_str(&ts_type_def);
|
||||
content.push_str("\n\n");
|
||||
}
|
||||
GeneratorOutput::Text {
|
||||
path: output(crate::TYPESCRIPT_PACKAGE, "types.d.ts"),
|
||||
content: format_typescript(&content),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Untagged enums: "type Expression = BooleanLiteral | NullLiteral"
|
||||
// Tagged enums: "type PropertyKind = 'init' | 'get' | 'set'"
|
||||
fn typescript_enum(def: &EnumDef) -> Option<String> {
|
||||
if def.markers.estree.custom_ts_def {
|
||||
return None;
|
||||
}
|
||||
|
||||
let union = if def.markers.estree.untagged {
|
||||
def.all_variants().map(|var| type_to_string(var.fields[0].typ.name())).join(" | ")
|
||||
} else {
|
||||
def.all_variants().map(|var| format!("'{}'", enum_variant_name(var, def))).join(" | ")
|
||||
};
|
||||
let ident = def.ident();
|
||||
Some(format!("export type {ident} = {union};"))
|
||||
}
|
||||
|
||||
fn typescript_struct(def: &StructDef) -> String {
|
||||
let ident = def.ident();
|
||||
let mut fields = String::new();
|
||||
let mut extends = vec![];
|
||||
|
||||
if let Some(type_tag) = get_type_tag(def) {
|
||||
fields.push_str(&format!("\n\ttype: '{type_tag}';"));
|
||||
}
|
||||
|
||||
for field in &def.fields {
|
||||
if field.markers.derive_attributes.estree.skip {
|
||||
continue;
|
||||
}
|
||||
let ty = match &field.markers.derive_attributes.tsify_type {
|
||||
Some(ty) => ty.clone(),
|
||||
None => type_to_string(field.typ.name()),
|
||||
};
|
||||
|
||||
if field.markers.derive_attributes.estree.flatten {
|
||||
extends.push(ty);
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = match &field.markers.derive_attributes.estree.rename {
|
||||
Some(rename) => rename.to_string(),
|
||||
None => field.name.clone().unwrap().to_case(Case::Camel),
|
||||
};
|
||||
|
||||
fields.push_str(&format!("\n\t{name}: {ty};"));
|
||||
}
|
||||
|
||||
let extends_union = extends.iter().any(|it| it.contains('|'));
|
||||
|
||||
if extends_union {
|
||||
let extends =
|
||||
if extends.is_empty() { String::new() } else { format!(" & {}", extends.join(" & ")) };
|
||||
format!("export type {ident} = ({{{fields}\n}}){extends};")
|
||||
} else {
|
||||
let extends = if extends.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!(" extends {}", extends.join(", "))
|
||||
};
|
||||
format!("export interface {ident}{extends} {{{fields}\n}}")
|
||||
}
|
||||
}
|
||||
|
||||
fn type_to_string(ty: &TypeName) -> String {
|
||||
match ty {
|
||||
TypeName::Ident(ident) => match ident.as_str() {
|
||||
"f64" | "f32" | "usize" | "u64" | "u32" | "u16" | "u8" | "i64" | "i32" | "i16"
|
||||
| "i8" => "number",
|
||||
"bool" => "boolean",
|
||||
"str" | "String" | "Atom" | "CompactStr" => "string",
|
||||
ty => ty,
|
||||
}
|
||||
.to_string(),
|
||||
TypeName::Vec(type_name) => format!("Array<{}>", type_to_string(type_name)),
|
||||
TypeName::Box(type_name) | TypeName::Ref(type_name) | TypeName::Complex(type_name) => {
|
||||
type_to_string(type_name)
|
||||
}
|
||||
TypeName::Opt(type_name) => format!("({}) | null", type_to_string(type_name)),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_typescript(source_text: &str) -> String {
|
||||
let mut dprint = Command::new("dprint")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.args(["fmt", "--stdin", "types.d.ts"])
|
||||
.spawn()
|
||||
.expect("Failed to run dprint (is it installed?)");
|
||||
|
||||
let stdin = dprint.stdin.as_mut().unwrap();
|
||||
stdin.write_all(source_text.as_bytes()).unwrap();
|
||||
stdin.flush().unwrap();
|
||||
|
||||
let output = dprint.wait_with_output().unwrap();
|
||||
String::from_utf8(output.stdout).unwrap()
|
||||
}
|
||||
|
||||
// Unusable until oxc_prettier supports comments
|
||||
// fn format_typescript(source_text: &str) -> String {
|
||||
// let allocator = Allocator::default();
|
||||
// let source_type = SourceType::ts();
|
||||
// let ret = Parser::new(&allocator, source_text, source_type)
|
||||
// .with_options(ParseOptions { preserve_parens: false, ..ParseOptions::default() })
|
||||
// .parse();
|
||||
// Prettier::new(
|
||||
// &allocator,
|
||||
// PrettierOptions {
|
||||
// semi: true,
|
||||
// trailing_comma: TrailingComma::All,
|
||||
// single_quote: true,
|
||||
// ..PrettierOptions::default()
|
||||
// },
|
||||
// )
|
||||
// .build(&ret.program)
|
||||
// }
|
||||
|
|
@ -24,7 +24,7 @@ use derives::{
|
|||
use fmt::cargo_fmt;
|
||||
use generators::{
|
||||
AssertLayouts, AstBuilderGenerator, AstKindGenerator, Generator, GeneratorOutput,
|
||||
VisitGenerator, VisitMutGenerator,
|
||||
TypescriptGenerator, VisitGenerator, VisitMutGenerator,
|
||||
};
|
||||
use passes::{CalcLayout, Linker};
|
||||
use util::{write_all_to, NormalizeError};
|
||||
|
|
@ -43,6 +43,7 @@ static SOURCE_PATHS: &[&str] = &[
|
|||
];
|
||||
|
||||
const AST_CRATE: &str = "crates/oxc_ast";
|
||||
const TYPESCRIPT_PACKAGE: &str = "npm/oxc-types";
|
||||
|
||||
type Result<R> = std::result::Result<R, String>;
|
||||
type TypeId = usize;
|
||||
|
|
@ -84,6 +85,7 @@ fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
|||
.generate(AstBuilderGenerator)
|
||||
.generate(VisitGenerator)
|
||||
.generate(VisitMutGenerator)
|
||||
.generate(TypescriptGenerator)
|
||||
.run()?;
|
||||
|
||||
if !cli_options.dry_run {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@
|
|||
"node",
|
||||
"web"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@oxc/types": "workspace:^"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm run build-node && pnpm run build-web && pnpm run copy-files && pnpm run clean-files",
|
||||
"build-node": "pnpm run build-base --target nodejs --out-dir ../../npm/parser-wasm/node .",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@ use serde::{Deserialize, Serialize};
|
|||
use tsify::Tsify;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
|
||||
const TS_APPEND_CONTENT: &'static str = r#"
|
||||
import type { Program } from "@oxc/types";
|
||||
export * from "@oxc/types";
|
||||
"#;
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Tsify)]
|
||||
#[tsify(from_wasm_abi)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
|
|
|||
Loading…
Reference in a new issue