Skip to content

Commit

Permalink
feat(napi/parser): introduce experimental magic string
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen committed Dec 10, 2024
1 parent 5806942 commit 5ca3be0
Show file tree
Hide file tree
Showing 11 changed files with 340 additions and 36 deletions.
60 changes: 51 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ unicode-id-start = "1"
oxc-browserslist = "1.1.0"
oxc_index = "2"
oxc_resolver = "2.1.1"
oxc_sourcemap = "1.0.3"
oxc_sourcemap = "1"

#
allocator-api2 = "0.2.21"
Expand Down
3 changes: 3 additions & 0 deletions napi/parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ oxc_ast = { workspace = true, features = ["serialize"] } # enable feature only
oxc_napi = { workspace = true }

rustc-hash = { workspace = true }
self_cell = "1.0.4"
serde_json = { workspace = true }
string_wizard = { version = "0.0.23", features = ["sourcemap"] }
# oxc_sourcemap = { workspace = true, features = ["napi"] }

napi = { workspace = true, features = ["async"] }
napi-derive = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions napi/parser/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}

module.exports.MagicString = nativeBinding.MagicString
module.exports.ParseResult = nativeBinding.ParseResult
module.exports.ExportExportNameKind = nativeBinding.ExportExportNameKind
module.exports.ExportImportNameKind = nativeBinding.ExportImportNameKind
module.exports.ExportLocalNameKind = nativeBinding.ExportLocalNameKind
Expand Down
34 changes: 27 additions & 7 deletions napi/parser/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@
/* eslint-disable */

export * from '@oxc-project/types';
export declare class MagicString {
sourceText(start: number, end: number): string
length(): number
toString(): string
append(input: string): this
appendLeft(index: number, input: string): this
appendRight(index: number, input: string): this
indent(): this
prepend(input: string): this
prependLeft(index: number, input: string): this
prependRight(index: number, input: string): this
relocate(start: number, end: number, to: number): this
remove(start: number, end: number): this
}

export declare class ParseResult {
get program(): import("@oxc-project/types").Program
get module(): EcmaScriptModule
get comments(): Array<Comment>
get errors(): Array<Error>
get magicString(): MagicString
}

export interface Comment {
type: 'Line' | 'Block'
value: string
Expand Down Expand Up @@ -108,20 +131,17 @@ export declare const enum ImportNameKind {
Default = 'Default'
}

export interface OverwriteOptions {
contentOnly: boolean
}

/**
* Parse asynchronously.
*
* Note: This function can be slower than `parseSync` due to the overhead of spawning a thread.
*/
export declare function parseAsync(filename: string, sourceText: string, options?: ParserOptions | undefined | null): Promise<ParseResult>

export interface ParseResult {
program: import("@oxc-project/types").Program
module: EcmaScriptModule
comments: Array<Comment>
errors: Array<Error>
}

export interface ParserOptions {
sourceType?: 'script' | 'module' | 'unambiguous' | undefined
/** Treat the source text as `js`, `jsx`, `ts`, or `tsx`. */
Expand Down
42 changes: 36 additions & 6 deletions napi/parser/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
const bindings = require('./bindings.js');

module.exports.MagicString = bindings.MagicString;
module.exports.ParseResult = bindings.ParseResult;
module.exports.ExportExportNameKind = bindings.ExportExportNameKind;
module.exports.ExportImportNameKind = bindings.ExportImportNameKind;
module.exports.ExportLocalNameKind = bindings.ExportLocalNameKind;
module.exports.ImportNameKind = bindings.ImportNameKind;
module.exports.parseWithoutReturn = bindings.parseWithoutReturn;
module.exports.Severity = bindings.Severity;

function wrap(result) {
let program, module, comments, errors, magicString;
return {
get program() {
if (!program) program = JSON.parse(result.program);
return program;
},
get module() {
if (!module) module = result.module;
return module;
},
get comments() {
if (!comments) comments = result.comments;
return comments;
},
get errors() {
if (!errors) errors = result.errors;
return errors;
},
get magicString() {
if (!magicString) magicString = result.magicString;
return magicString;
},
};
}

module.exports.parseAsync = async function parseAsync(...args) {
const result = await bindings.parseAsync(...args);
result.program = JSON.parse(result.program);
return result;
return wrap(await bindings.parseAsync(...args));
};

module.exports.parseSync = function parseSync(...args) {
const result = bindings.parseSync(...args);
result.program = JSON.parse(result.program);
return result;
return wrap(bindings.parseSync(...args));
};
21 changes: 14 additions & 7 deletions napi/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
)]

mod convert;
mod magic_string;
mod types;

use std::mem;

use napi::{bindgen_prelude::AsyncTask, Task};
use napi_derive::napi;

Expand All @@ -16,7 +19,10 @@ use oxc::{
};
use oxc_napi::Error;

pub use crate::types::{Comment, EcmaScriptModule, ParseResult, ParserOptions};
pub use crate::{
magic_string::MagicString,
types::{Comment, EcmaScriptModule, ParseResult, ParserOptions},
};

fn get_source_type(filename: &str, options: &ParserOptions) -> SourceType {
match options.lang.as_deref() {
Expand Down Expand Up @@ -62,10 +68,10 @@ pub fn parse_without_return(filename: String, source_text: String, options: Opti
parse(&allocator, source_type, &source_text, &options);
}

fn parse_with_return(filename: &str, source_text: &str, options: &ParserOptions) -> ParseResult {
fn parse_with_return(filename: &str, source_text: String, options: &ParserOptions) -> ParseResult {
let allocator = Allocator::default();
let source_type = get_source_type(filename, options);
let ret = parse(&allocator, source_type, source_text, options);
let ret = parse(&allocator, source_type, &source_text, options);
let program = serde_json::to_string(&ret.program).unwrap();

let errors = ret.errors.into_iter().map(Error::from).collect::<Vec<_>>();
Expand All @@ -79,14 +85,14 @@ fn parse_with_return(filename: &str, source_text: &str, options: &ParserOptions)
CommentKind::Line => String::from("Line"),
CommentKind::Block => String::from("Block"),
},
value: comment.content_span().source_text(source_text).to_string(),
value: comment.content_span().source_text(&source_text).to_string(),
start: comment.span.start,
end: comment.span.end,
})
.collect::<Vec<Comment>>();

let module = EcmaScriptModule::from(&ret.module_record);
ParseResult { program, module, comments, errors }
ParseResult { source_text, program, module, comments, errors }
}

/// Parse synchronously.
Expand All @@ -97,7 +103,7 @@ pub fn parse_sync(
options: Option<ParserOptions>,
) -> ParseResult {
let options = options.unwrap_or_default();
parse_with_return(&filename, &source_text, &options)
parse_with_return(&filename, source_text, &options)
}

pub struct ResolveTask {
Expand All @@ -112,7 +118,8 @@ impl Task for ResolveTask {
type Output = ParseResult;

fn compute(&mut self) -> napi::Result<Self::Output> {
Ok(parse_with_return(&self.filename, &self.source_text, &self.options))
let source_text = mem::take(&mut self.source_text);
Ok(parse_with_return(&self.filename, source_text, &self.options))
}

fn resolve(&mut self, _: napi::Env, result: Self::Output) -> napi::Result<Self::JsValue> {
Expand Down
Loading

0 comments on commit 5ca3be0

Please sign in to comment.