oxc 0.1.0-arm-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +437 -0
  4. data/ext/oxc/extconf.rb +123 -0
  5. data/ext/oxc/include/oxc.h +40 -0
  6. data/ext/oxc/oxc.c +136 -0
  7. data/lib/oxc/3.2/oxc.so +0 -0
  8. data/lib/oxc/3.3/oxc.so +0 -0
  9. data/lib/oxc/3.4/oxc.so +0 -0
  10. data/lib/oxc/4.0/oxc.so +0 -0
  11. data/lib/oxc/backend.rb +41 -0
  12. data/lib/oxc/diagnosed.rb +33 -0
  13. data/lib/oxc/diagnostic.rb +86 -0
  14. data/lib/oxc/errors.rb +26 -0
  15. data/lib/oxc/minifier.rb +31 -0
  16. data/lib/oxc/minify_result.rb +25 -0
  17. data/lib/oxc/options.rb +113 -0
  18. data/lib/oxc/parse_result.rb +106 -0
  19. data/lib/oxc/result.rb +51 -0
  20. data/lib/oxc/transform_result.rb +47 -0
  21. data/lib/oxc/transformer.rb +31 -0
  22. data/lib/oxc/version.rb +5 -0
  23. data/lib/oxc.rb +52 -0
  24. data/licenses/README.md +12 -0
  25. data/licenses/oxc-MIT.txt +22 -0
  26. data/licenses/oxc-THIRD-PARTY.txt +763 -0
  27. data/oxc.gemspec +43 -0
  28. data/rust/Cargo.lock +1436 -0
  29. data/rust/Cargo.toml +32 -0
  30. data/rust/build.rs +52 -0
  31. data/rust/cbindgen.toml +24 -0
  32. data/rust/rustfmt.toml +3 -0
  33. data/rust/src/diagnostic.rs +75 -0
  34. data/rust/src/lib.rs +288 -0
  35. data/rust/src/module_record.rs +262 -0
  36. data/rust/src/options.rs +744 -0
  37. data/rust/src/parse.rs +93 -0
  38. data/rust/src/result.rs +55 -0
  39. data/rust/src/source_type.rs +26 -0
  40. data/rust/src/symbols.rs +101 -0
  41. data/rust/src/transform.rs +116 -0
  42. data/sig/oxc/backend.rbs +29 -0
  43. data/sig/oxc/diagnosed.rbs +23 -0
  44. data/sig/oxc/diagnostic.rbs +57 -0
  45. data/sig/oxc/errors.rbs +31 -0
  46. data/sig/oxc/minifier.rbs +21 -0
  47. data/sig/oxc/minify_result.rbs +11 -0
  48. data/sig/oxc/options.rbs +42 -0
  49. data/sig/oxc/parse_result.rbs +61 -0
  50. data/sig/oxc/result.rbs +32 -0
  51. data/sig/oxc/transform_result.rbs +22 -0
  52. data/sig/oxc/transformer.rbs +21 -0
  53. data/sig/oxc/types.rbs +96 -0
  54. data/sig/oxc/version.rbs +5 -0
  55. data/sig/oxc.rbs +15 -0
  56. metadata +107 -0
data/rust/Cargo.toml ADDED
@@ -0,0 +1,32 @@
1
+ [workspace]
2
+
3
+ [package]
4
+ name = "oxc-ruby-ffi"
5
+ version = "0.1.0"
6
+ edition = "2021"
7
+ authors = ["Marco Roth <marco.roth@intergga.ch>"]
8
+ description = "C FFI bindings for oxc, used by the oxc gem"
9
+ license = "MIT"
10
+ repository = "https://github.com/marcoroth/oxc-ruby"
11
+ publish = false
12
+
13
+ [lib]
14
+ name = "oxc_ffi"
15
+ path = "src/lib.rs"
16
+ crate-type = ["cdylib", "staticlib", "rlib"]
17
+
18
+ [dependencies]
19
+ oxc = { version = "=0.147.0", features = ["full", "serialize"] }
20
+ oxc_sourcemap = "8"
21
+ serde = { version = "1", features = ["derive"] }
22
+ serde_json = { version = "1", features = ["raw_value"] }
23
+
24
+ [build-dependencies]
25
+ cbindgen = "0.28"
26
+
27
+ [profile.release]
28
+ opt-level = 3
29
+ lto = "fat"
30
+ codegen-units = 1
31
+ strip = "symbols"
32
+ panic = "unwind"
data/rust/build.rs ADDED
@@ -0,0 +1,52 @@
1
+ use std::env;
2
+ use std::fs;
3
+ use std::path::PathBuf;
4
+
5
+ fn main() {
6
+ let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
7
+ let header_path = PathBuf::from(&crate_dir).join("../ext/oxc/include/oxc.h");
8
+
9
+ if let Ok(bindings) = cbindgen::generate(&crate_dir) {
10
+ if let Some(parent) = header_path.parent() {
11
+ let _ = std::fs::create_dir_all(parent);
12
+ }
13
+
14
+ bindings.write_to_file(&header_path);
15
+ }
16
+
17
+ let lock_path = PathBuf::from(&crate_dir).join("Cargo.lock");
18
+
19
+ println!("cargo:rerun-if-changed={}", lock_path.display());
20
+
21
+ println!(
22
+ "cargo:rerun-if-changed={}",
23
+ PathBuf::from(&crate_dir).join("src").display()
24
+ );
25
+
26
+ println!(
27
+ "cargo:rerun-if-changed={}",
28
+ PathBuf::from(&crate_dir).join("cbindgen.toml").display()
29
+ );
30
+
31
+ println!("cargo:rustc-env=OXC_VERSION={}", locked_version(&lock_path, "oxc"));
32
+ }
33
+
34
+ fn locked_version(lock_path: &PathBuf, package: &str) -> String {
35
+ let Ok(lock) = fs::read_to_string(lock_path) else {
36
+ return "unknown".to_string();
37
+ };
38
+
39
+ let mut lines = lock.lines();
40
+
41
+ while let Some(line) = lines.next() {
42
+ if line.trim() != format!("name = \"{package}\"") {
43
+ continue;
44
+ }
45
+
46
+ if let Some(version) = lines.next().and_then(|next| next.trim().strip_prefix("version = ")) {
47
+ return version.trim_matches('"').to_string();
48
+ }
49
+ }
50
+
51
+ "unknown".to_string()
52
+ }
@@ -0,0 +1,24 @@
1
+ language = "C"
2
+ header = """/* Generated by cbindgen — do not edit manually */
3
+
4
+ #include <stdbool.h>
5
+ #include <stdint.h>
6
+ #include <stddef.h>"""
7
+ include_guard = "OXC_H"
8
+ no_includes = true
9
+
10
+ [export]
11
+ include = [
12
+ "OxcResult",
13
+ "OxcErrorCode",
14
+ ]
15
+
16
+ [enum]
17
+ rename_variants = "ScreamingSnakeCase"
18
+ prefix_with_name = true
19
+
20
+ [fn]
21
+ sort_by = "None"
22
+
23
+ [parse]
24
+ parse_deps = false
data/rust/rustfmt.toml ADDED
@@ -0,0 +1,3 @@
1
+ tab_spaces = 2
2
+ max_width = 120
3
+ edition = "2021"
@@ -0,0 +1,75 @@
1
+ use std::sync::Arc;
2
+
3
+ use oxc::diagnostics::{LabeledSpan, NamedSource, OxcDiagnostic};
4
+ use serde::Serialize;
5
+
6
+ #[derive(Debug, Serialize)]
7
+ pub struct Diagnostic {
8
+ pub severity: &'static str,
9
+ pub message: String,
10
+ pub labels: Vec<Label>,
11
+ #[serde(skip_serializing_if = "Option::is_none")]
12
+ pub help: Option<String>,
13
+ #[serde(skip_serializing_if = "Option::is_none")]
14
+ pub codeframe: Option<String>,
15
+ }
16
+
17
+ #[derive(Debug, Serialize)]
18
+ pub struct Label {
19
+ #[serde(skip_serializing_if = "Option::is_none")]
20
+ pub message: Option<String>,
21
+ pub start: u32,
22
+ pub end: u32,
23
+ }
24
+
25
+ impl Diagnostic {
26
+ pub fn from_diagnostics(
27
+ filename: &str,
28
+ source_text: &str,
29
+ diagnostics: impl IntoIterator<Item = OxcDiagnostic>,
30
+ ) -> Vec<Self> {
31
+ let diagnostics = diagnostics.into_iter().collect::<Vec<_>>();
32
+
33
+ if diagnostics.is_empty() {
34
+ return Vec::new();
35
+ }
36
+
37
+ let source = Arc::new(NamedSource::new(filename, source_text.to_string()));
38
+
39
+ diagnostics
40
+ .into_iter()
41
+ .map(|diagnostic| Self::from_diagnostic(&source, diagnostic))
42
+ .collect()
43
+ }
44
+
45
+ fn from_diagnostic(source: &Arc<NamedSource<String>>, diagnostic: OxcDiagnostic) -> Self {
46
+ let severity = match diagnostic.severity {
47
+ oxc::diagnostics::Severity::Error => "error",
48
+ oxc::diagnostics::Severity::Warning => "warning",
49
+ oxc::diagnostics::Severity::Advice => "advice",
50
+ };
51
+
52
+ let labels = diagnostic.labels.iter().map(Label::from).collect::<Vec<_>>();
53
+ let message = diagnostic.message.to_string();
54
+ let help = diagnostic.help.as_ref().map(ToString::to_string);
55
+ let codeframe = Some(diagnostic.render_with_source_code(Arc::clone(source)));
56
+
57
+ Self {
58
+ severity,
59
+ message,
60
+ labels,
61
+ help,
62
+ codeframe,
63
+ }
64
+ }
65
+ }
66
+
67
+ impl From<&LabeledSpan> for Label {
68
+ fn from(label: &LabeledSpan) -> Self {
69
+ Self {
70
+ message: label.label().map(ToString::to_string),
71
+ start: label.offset(),
72
+ end: label.offset() + label.len(),
73
+ }
74
+ }
75
+ }
data/rust/src/lib.rs ADDED
@@ -0,0 +1,288 @@
1
+ //! C FFI bindings for oxc.
2
+ //!
3
+ //! # Safety
4
+ //!
5
+ //! Every function here requires that pointer arguments are valid, NUL-terminated C strings unless
6
+ //! documented as nullable. Returned pointers are owned by the caller and must be released with
7
+ //! `oxc_string_free` or `oxc_result_free`.
8
+
9
+ #![allow(clippy::missing_safety_doc)]
10
+
11
+ mod diagnostic;
12
+ mod module_record;
13
+ mod options;
14
+ mod parse;
15
+ mod result;
16
+ mod source_type;
17
+ mod symbols;
18
+ mod transform;
19
+
20
+ use std::any::Any;
21
+ use std::ffi::{CStr, CString};
22
+ use std::os::raw::c_char;
23
+ use std::panic::{self, AssertUnwindSafe};
24
+ use std::ptr;
25
+
26
+ use oxc::allocator::Allocator;
27
+ use oxc::codegen::Codegen;
28
+ use oxc::minifier::Minifier;
29
+ use oxc::parser::Parser;
30
+ use oxc::CompilerInterface;
31
+ use serde::de::DeserializeOwned;
32
+
33
+ use crate::diagnostic::Diagnostic;
34
+ use crate::options::{MinifyOptions, ParseOptions, TransformOptions};
35
+ use crate::parse::parse_source;
36
+ use crate::result::{MinifyPayload, TransformPayload};
37
+ use crate::source_type::source_type_for;
38
+ use crate::transform::Compiler;
39
+
40
+ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
41
+ pub const OXC_VERSION: &str = env!("OXC_VERSION");
42
+
43
+ #[repr(C)]
44
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
45
+ pub enum OxcErrorCode {
46
+ None = 0,
47
+ Option,
48
+ Encoding,
49
+ Transform,
50
+ Internal,
51
+ Panic,
52
+ }
53
+
54
+ #[repr(C)]
55
+ pub struct OxcResult {
56
+ pub value: *mut c_char,
57
+ pub value_len: usize,
58
+ pub error: *mut c_char,
59
+ pub code: OxcErrorCode,
60
+ }
61
+
62
+ impl OxcResult {
63
+ pub fn ok(value: String) -> Self {
64
+ let len = value.len();
65
+
66
+ Self {
67
+ value: into_c_string(value),
68
+ value_len: len,
69
+ error: ptr::null_mut(),
70
+ code: OxcErrorCode::None,
71
+ }
72
+ }
73
+
74
+ pub fn err(code: OxcErrorCode, message: impl AsRef<str>) -> Self {
75
+ Self {
76
+ value: ptr::null_mut(),
77
+ value_len: 0,
78
+ error: into_c_string(message.as_ref()),
79
+ code,
80
+ }
81
+ }
82
+ }
83
+
84
+ pub struct Failure {
85
+ code: OxcErrorCode,
86
+ message: String,
87
+ }
88
+
89
+ impl Failure {
90
+ pub fn option(message: impl Into<String>) -> Self {
91
+ Self {
92
+ code: OxcErrorCode::Option,
93
+ message: message.into(),
94
+ }
95
+ }
96
+
97
+ pub fn encoding(message: impl Into<String>) -> Self {
98
+ Self {
99
+ code: OxcErrorCode::Encoding,
100
+ message: message.into(),
101
+ }
102
+ }
103
+ }
104
+
105
+ fn into_c_string(value: impl Into<Vec<u8>>) -> *mut c_char {
106
+ CString::new(value).unwrap_or_default().into_raw()
107
+ }
108
+
109
+ unsafe fn borrow_str<'a>(pointer: *const c_char, label: &str) -> Result<&'a str, Failure> {
110
+ if pointer.is_null() {
111
+ return Err(Failure::encoding(format!("{label} is null")));
112
+ }
113
+
114
+ CStr::from_ptr(pointer)
115
+ .to_str()
116
+ .map_err(|error| Failure::encoding(format!("Invalid UTF-8 in {label}: {error}")))
117
+ }
118
+
119
+ unsafe fn borrow_options<T: Default + DeserializeOwned>(pointer: *const c_char) -> Result<T, Failure> {
120
+ if pointer.is_null() {
121
+ return Ok(T::default());
122
+ }
123
+
124
+ let json = borrow_str(pointer, "options")?;
125
+
126
+ if json.trim().is_empty() {
127
+ return Ok(T::default());
128
+ }
129
+
130
+ serde_json::from_str(json).map_err(|error| Failure::option(format!("Invalid options: {error}")))
131
+ }
132
+
133
+ fn panic_message(payload: &Box<dyn Any + Send>) -> String {
134
+ if let Some(message) = payload.downcast_ref::<&str>() {
135
+ return (*message).to_string();
136
+ }
137
+
138
+ if let Some(message) = payload.downcast_ref::<String>() {
139
+ return message.clone();
140
+ }
141
+
142
+ "oxc panicked".to_string()
143
+ }
144
+
145
+ fn answer<T: serde::Serialize>(outcome: Result<T, Failure>) -> OxcResult {
146
+ match outcome {
147
+ Ok(payload) => match serde_json::to_string(&payload) {
148
+ Ok(json) => OxcResult::ok(json),
149
+ Err(error) => OxcResult::err(
150
+ OxcErrorCode::Internal,
151
+ format!("Failed to serialize the result: {error}"),
152
+ ),
153
+ },
154
+ Err(failure) => OxcResult::err(failure.code, failure.message),
155
+ }
156
+ }
157
+
158
+ pub fn guard<T: serde::Serialize>(call: impl FnOnce() -> Result<T, Failure>) -> OxcResult {
159
+ match panic::catch_unwind(AssertUnwindSafe(call)) {
160
+ Ok(outcome) => answer(outcome),
161
+ Err(payload) => OxcResult::err(OxcErrorCode::Panic, panic_message(&payload)),
162
+ }
163
+ }
164
+
165
+ fn minify_source(source: &str, options: &MinifyOptions) -> Result<MinifyPayload, Failure> {
166
+ let filename = options.filename.clone().unwrap_or_default();
167
+
168
+ let minifier_options = options.to_minifier_options().map_err(Failure::option)?;
169
+ let mut codegen_options = options.to_codegen_options().map_err(Failure::option)?;
170
+
171
+ let source_type =
172
+ source_type_for(&filename, options.lang.as_deref(), options.source_type.as_deref()).map_err(Failure::option)?;
173
+
174
+ let allocator = Allocator::default();
175
+ let parsed = Parser::new(&allocator, source, source_type).parse();
176
+
177
+ let mut program = parsed.program;
178
+
179
+ let minified = Minifier::new(minifier_options).minify(&allocator, &mut program);
180
+
181
+ if !options.sourcemap {
182
+ codegen_options.source_map_path = None;
183
+ }
184
+
185
+ let printed = Codegen::new()
186
+ .with_options(codegen_options)
187
+ .with_scoping(minified.scoping)
188
+ .build(&program);
189
+
190
+ let map = printed.map.map(|map| map.to_json_string());
191
+
192
+ let legal_comments = printed
193
+ .legal_comments
194
+ .iter()
195
+ .map(|comment| comment.span.source_text(source).to_string())
196
+ .collect();
197
+
198
+ Ok(MinifyPayload {
199
+ code: printed.code,
200
+ map,
201
+ legal_comments,
202
+ errors: Diagnostic::from_diagnostics(&filename, source, parsed.diagnostics),
203
+ panicked: parsed.panicked,
204
+ })
205
+ }
206
+
207
+ fn transform_source(source: &str, options: &TransformOptions) -> Result<TransformPayload, Failure> {
208
+ let filename = options.filename.clone().unwrap_or_default();
209
+
210
+ let source_type =
211
+ source_type_for(&filename, options.lang.as_deref(), options.source_type.as_deref()).map_err(Failure::option)?;
212
+
213
+ let mut compiler = Compiler::new(options).map_err(Failure::option)?;
214
+
215
+ compiler.compile(source, source_type, std::path::Path::new(&filename));
216
+
217
+ let legal_comments = compiler
218
+ .legal_comments
219
+ .iter()
220
+ .map(|span| span.source_text(source).to_string())
221
+ .collect();
222
+
223
+ let panicked = compiler.code.is_empty() && !compiler.errors.is_empty();
224
+
225
+ Ok(TransformPayload {
226
+ code: compiler.code,
227
+ map: compiler.map,
228
+ declaration: compiler.declaration,
229
+ declaration_map: compiler.declaration_map,
230
+ legal_comments,
231
+ helpers_used: compiler.helpers_used,
232
+ errors: Diagnostic::from_diagnostics(&filename, source, compiler.errors),
233
+ panicked,
234
+ })
235
+ }
236
+
237
+ #[no_mangle]
238
+ pub unsafe extern "C" fn oxc_parse(source: *const c_char, options_json: *const c_char) -> OxcResult {
239
+ guard(|| {
240
+ let source = borrow_str(source, "source")?;
241
+ let options = borrow_options::<ParseOptions>(options_json)?;
242
+
243
+ parse_source(source, &options).map_err(Failure::option)
244
+ })
245
+ }
246
+
247
+ #[no_mangle]
248
+ pub unsafe extern "C" fn oxc_transform(source: *const c_char, options_json: *const c_char) -> OxcResult {
249
+ guard(|| {
250
+ let source = borrow_str(source, "source")?;
251
+ let options = borrow_options::<TransformOptions>(options_json)?;
252
+
253
+ transform_source(source, &options)
254
+ })
255
+ }
256
+
257
+ #[no_mangle]
258
+ pub unsafe extern "C" fn oxc_minify(source: *const c_char, options_json: *const c_char) -> OxcResult {
259
+ guard(|| {
260
+ let source = borrow_str(source, "source")?;
261
+ let options = borrow_options::<MinifyOptions>(options_json)?;
262
+
263
+ minify_source(source, &options)
264
+ })
265
+ }
266
+
267
+ #[no_mangle]
268
+ pub unsafe extern "C" fn oxc_version() -> *mut c_char {
269
+ into_c_string(VERSION)
270
+ }
271
+
272
+ #[no_mangle]
273
+ pub unsafe extern "C" fn oxc_oxc_version() -> *mut c_char {
274
+ into_c_string(OXC_VERSION)
275
+ }
276
+
277
+ #[no_mangle]
278
+ pub unsafe extern "C" fn oxc_string_free(value: *mut c_char) {
279
+ if !value.is_null() {
280
+ drop(CString::from_raw(value));
281
+ }
282
+ }
283
+
284
+ #[no_mangle]
285
+ pub unsafe extern "C" fn oxc_result_free(result: OxcResult) {
286
+ oxc_string_free(result.value);
287
+ oxc_string_free(result.error);
288
+ }