Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ oxc_estree = { version = "0.39.0", path = "crates/oxc_estree" }
oxc_isolated_declarations = { version = "0.39.0", path = "crates/oxc_isolated_declarations" }
oxc_mangler = { version = "0.39.0", path = "crates/oxc_mangler" }
oxc_minifier = { version = "0.39.0", path = "crates/oxc_minifier" }
oxc_napi = { version = "0.39.0", path = "crates/oxc_napi" }
oxc_parser = { version = "0.39.0", path = "crates/oxc_parser" }
oxc_regular_expression = { version = "0.39.0", path = "crates/oxc_regular_expression" }
oxc_semantic = { version = "0.39.0", path = "crates/oxc_semantic" }
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_diagnostics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Feature gating napi in other crates will lead to symbol not found when compiling,
use this crate for common napi interfaces.
28 changes: 28 additions & 0 deletions crates/oxc_napi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "oxc_napi"
version = "0.39.0"
authors.workspace = true
categories.workspace = true
edition.workspace = true
homepage.workspace = true
include = ["/src"]
keywords.workspace = true
license.workspace = true
publish = true
repository.workspace = true
rust-version.workspace = true
description.workspace = true

[lints]
workspace = true

[lib]
doctest = false

[dependencies]
napi = { workspace = true }
napi-derive = { workspace = true }
oxc_diagnostics = { workspace = true }

[package.metadata.cargo-shear]
ignored = ["napi"]
68 changes: 68 additions & 0 deletions crates/oxc_napi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use napi_derive::napi;

use oxc_diagnostics::{LabeledSpan, OxcDiagnostic};

#[napi(object)]
pub struct Error {
pub severity: Severity,
pub message: String,
pub labels: Vec<ErrorLabel>,
pub help_message: Option<String>,
}

impl Error {
pub fn new(message: String) -> Self {
Self { severity: Severity::Error, message, labels: vec![], help_message: None }
}
}

impl From<OxcDiagnostic> for Error {
fn from(diagnostic: OxcDiagnostic) -> Self {
let labels = diagnostic
.labels
.as_ref()
.map(|labels| labels.iter().map(ErrorLabel::from).collect::<Vec<_>>())
.unwrap_or_default();
Self {
severity: Severity::from(diagnostic.severity),
message: diagnostic.message.to_string(),
labels,
help_message: diagnostic.help.as_ref().map(ToString::to_string),
}
}
}

#[napi(object)]
pub struct ErrorLabel {
pub message: Option<String>,
pub start: u32,
pub end: u32,
}

impl From<&LabeledSpan> for ErrorLabel {
#[allow(clippy::cast_possible_truncation)]
fn from(label: &LabeledSpan) -> Self {
Self {
message: label.label().map(ToString::to_string),
start: label.offset() as u32,
end: (label.offset() + label.len()) as u32,
}
}
}

#[napi(string_enum)]
pub enum Severity {
Error,
Warning,
Advice,
}

impl From<oxc_diagnostics::Severity> for Severity {
fn from(value: oxc_diagnostics::Severity) -> Self {
match value {
oxc_diagnostics::Severity::Error => Self::Error,
oxc_diagnostics::Severity::Warning => Self::Warning,
oxc_diagnostics::Severity::Advice => Self::Advice,
}
}
}
1 change: 1 addition & 0 deletions napi/parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ doctest = false

[dependencies]
oxc = { workspace = true, features = ["serialize"] }
oxc_napi = { workspace = true }

rustc-hash = { workspace = true }
serde_json = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions napi/parser/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,3 +368,4 @@ module.exports.ImportNameKind = nativeBinding.ImportNameKind
module.exports.parseAsync = nativeBinding.parseAsync
module.exports.parseSync = nativeBinding.parseSync
module.exports.parseWithoutReturn = nativeBinding.parseWithoutReturn
module.exports.Severity = nativeBinding.Severity
21 changes: 20 additions & 1 deletion napi/parser/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ export interface EcmaScriptModule {
importMetas: Array<Span>
}

export interface Error {
severity: Severity
message: string
labels: Array<ErrorLabel>
helpMessage?: string
}

export interface ErrorLabel {
message?: string
start: number
end: number
}

export interface ExportExportName {
kind: ExportExportNameKind
name?: string
Expand Down Expand Up @@ -106,7 +119,7 @@ export interface ParseResult {
program: import("@oxc-project/types").Program
module: EcmaScriptModule
comments: Array<Comment>
errors: Array<string>
errors: Array<Error>
}

export interface ParserOptions {
Expand Down Expand Up @@ -135,6 +148,12 @@ export declare function parseSync(filename: string, sourceText: string, options?
*/
export declare function parseWithoutReturn(filename: string, sourceText: string, options?: ParserOptions | undefined | null): void

export declare const enum Severity {
Error = 'Error',
Warning = 'Warning',
Advice = 'Advice'
}

export interface Span {
start: number
end: number
Expand Down
15 changes: 2 additions & 13 deletions napi/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@
mod convert;
mod types;

use std::sync::Arc;

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

use oxc::{
allocator::Allocator,
ast::CommentKind,
diagnostics::{Error, NamedSource},
parser::{ParseOptions, Parser, ParserReturn},
span::SourceType,
};
use oxc_napi::Error;

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

Expand Down Expand Up @@ -70,16 +68,7 @@ fn parse_with_return(filename: &str, source_text: &str, options: &ParserOptions)
let ret = parse(&allocator, source_type, source_text, options);
let program = serde_json::to_string(&ret.program).unwrap();

let errors = if ret.errors.is_empty() {
vec![]
} else {
let source = Arc::new(NamedSource::new(filename, source_text.to_string()));
ret.errors
.into_iter()
.map(|diagnostic| Error::from(diagnostic).with_source_code(Arc::clone(&source)))
.map(|error| format!("{error:?}"))
.collect()
};
let errors = ret.errors.into_iter().map(Error::from).collect::<Vec<_>>();

let comments = ret
.program
Expand Down
4 changes: 3 additions & 1 deletion napi/parser/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use napi_derive::napi;

use oxc_napi::Error;

#[napi(object)]
#[derive(Default)]
pub struct ParserOptions {
Expand All @@ -26,7 +28,7 @@ pub struct ParseResult {
pub program: String,
pub module: EcmaScriptModule,
pub comments: Vec<Comment>,
pub errors: Vec<String>,
pub errors: Vec<Error>,
}

#[napi(object)]
Expand Down
20 changes: 20 additions & 0 deletions napi/parser/test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,23 @@ describe('parse', () => {
expect(ret).toEqual(ret2);
});
});

describe('error', () => {
const code = 'asdf asdf';

it('returns structured error', () => {
const ret = parseSync('test.js', code);
expect(ret.errors.length).toBe(1);
expect(ret.errors[0]).toStrictEqual({
'helpMessage': 'Try insert a semicolon here',
'labels': [
{
'end': 4,
'start': 4,
},
],
'message': 'Expected a semicolon or an implicit semicolon after a statement, but found none',
'severity': 'Error',
});
});
});
1 change: 1 addition & 0 deletions napi/transform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ doctest = false

[dependencies]
oxc = { workspace = true, features = ["full"] }
oxc_napi = { workspace = true }
oxc_sourcemap = { workspace = true, features = ["napi", "rayon"] }

rustc-hash = { workspace = true }
Expand Down
23 changes: 21 additions & 2 deletions napi/transform/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ export interface CompilerAssumptions {
setPublicClassFields?: boolean
}

export interface Error {
severity: Severity
message: string
labels: Array<ErrorLabel>
helpMessage?: string
}

export interface ErrorLabel {
message?: string
start: number
end: number
}

export interface Es2015Options {
/** Transform arrow functions into function expressions. */
arrowFunction?: ArrowFunctionsOptions
Expand All @@ -44,7 +57,7 @@ export interface IsolatedDeclarationsOptions {
export interface IsolatedDeclarationsResult {
code: string
map?: SourceMap
errors: Array<string>
errors: Array<Error>
}

/**
Expand Down Expand Up @@ -158,6 +171,12 @@ export interface ReactRefreshOptions {
emitFullSignatures?: boolean
}

export declare const enum Severity {
Error = 'Error',
Warning = 'Warning',
Advice = 'Advice'
}

export interface SourceMap {
file?: string
mappings: string
Expand Down Expand Up @@ -271,7 +290,7 @@ export interface TransformResult {
* transformed code may still be available even if there are errors in this
* list.
*/
errors: Array<string>
errors: Array<Error>
}

export interface TypeScriptOptions {
Expand Down
1 change: 1 addition & 0 deletions napi/transform/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,5 @@ if (!nativeBinding) {
}

module.exports.isolatedDeclaration = nativeBinding.isolatedDeclaration
module.exports.Severity = nativeBinding.Severity
module.exports.transform = nativeBinding.transform
41 changes: 0 additions & 41 deletions napi/transform/src/errors.rs

This file was deleted.

Loading