rolldown 0.1.0-x86_64-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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +152 -0
  4. data/ext/rolldown/extconf.rb +123 -0
  5. data/ext/rolldown/include/rolldown.h +54 -0
  6. data/ext/rolldown/rolldown.c +130 -0
  7. data/lib/rolldown/3.2/rolldown.so +0 -0
  8. data/lib/rolldown/3.3/rolldown.so +0 -0
  9. data/lib/rolldown/3.4/rolldown.so +0 -0
  10. data/lib/rolldown/4.0/rolldown.so +0 -0
  11. data/lib/rolldown/asset.rb +33 -0
  12. data/lib/rolldown/backend.rb +36 -0
  13. data/lib/rolldown/build_result.rb +106 -0
  14. data/lib/rolldown/chunk.rb +70 -0
  15. data/lib/rolldown/diagnostic.rb +56 -0
  16. data/lib/rolldown/errors.rb +11 -0
  17. data/lib/rolldown/options.rb +152 -0
  18. data/lib/rolldown/version.rb +5 -0
  19. data/lib/rolldown.rb +50 -0
  20. data/licenses/README.md +8 -0
  21. data/licenses/rolldown-MIT.txt +25 -0
  22. data/licenses/rolldown-THIRD-PARTY.txt +33 -0
  23. data/rolldown.gemspec +43 -0
  24. data/rust/Cargo.lock +3086 -0
  25. data/rust/Cargo.toml +37 -0
  26. data/rust/build.rs +55 -0
  27. data/rust/cbindgen.toml +24 -0
  28. data/rust/rustfmt.toml +3 -0
  29. data/rust/src/build.rs +39 -0
  30. data/rust/src/lib.rs +92 -0
  31. data/rust/src/modules.rs +89 -0
  32. data/rust/src/options.rs +251 -0
  33. data/rust/src/payload.rs +104 -0
  34. data/rust/src/result.rs +49 -0
  35. data/sig/rolldown/asset.rbs +23 -0
  36. data/sig/rolldown/backend.rbs +26 -0
  37. data/sig/rolldown/build_result.rbs +47 -0
  38. data/sig/rolldown/chunk.rbs +39 -0
  39. data/sig/rolldown/diagnostic.rbs +35 -0
  40. data/sig/rolldown/errors.rbs +24 -0
  41. data/sig/rolldown/options.rbs +61 -0
  42. data/sig/rolldown/version.rbs +5 -0
  43. data/sig/rolldown.rbs +12 -0
  44. metadata +92 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: db51e0f0b374c08e6d794dfd1b38a295837ab1c390f7beea009e695545e7de50
4
+ data.tar.gz: fb62062954c11a87a2535e9e833d47df61da0f0dfbe5782b5ea41c3efa4b855b
5
+ SHA512:
6
+ metadata.gz: 8b8217626f836279f8aa27a59bc2c5da0a73576a07d2052edc8c05e45533289292edf8d78fb9311f5d1442a06475709cffa97acdf49d29410bbf339ee599f83e
7
+ data.tar.gz: 1a2a2d67df8dbf872223b6b08aaca57109de5219b0f00dadbb77f51d218fba46f3980d41decaa82cb8deb4f378615d3cfbac2fd81dbdc297a12db7f4f07b62b4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Marco Roth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ <h2 align="center">⬇️ Rolldown for Ruby</h2>
2
+
3
+ <h4 align="center">Blazing Fast Rust-based bundler for JavaScript.</h4>
4
+
5
+ <div align="center">Ruby bindings for <a href="https://rolldown.rs">Rolldown</a>, the Rust bundler behind Vite.</div><br/>
6
+
7
+ <p align="center">
8
+ <a href="https://rubygems.org/gems/rolldown"><img alt="Gem Version" src="https://img.shields.io/gem/v/rolldown"></a>
9
+ <a href="https://rolldown.rs"><img alt="Documentation" src="https://img.shields.io/badge/rolldown.rs-documentation-green"></a>
10
+ <a href="https://github.com/marcoroth/rolldown-ruby/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/github/license/marcoroth/rolldown-ruby"></a>
11
+ <a href="https://github.com/marcoroth/rolldown-ruby/issues"><img alt="Issues" src="https://img.shields.io/github/issues/marcoroth/rolldown-ruby"></a>
12
+ </p>
13
+
14
+ <br/>
15
+
16
+ ### What is Rolldown for Ruby?
17
+
18
+ Ruby bindings for [Rolldown](https://rolldown.rs), the Rust-based bundler for JavaScript. Bundle JavaScript from Ruby, without the need for a JavaScript runtime.
19
+
20
+ Everything here is Rolldown doing the work. For what the options mean and what it can do, [rolldown.rs](https://rolldown.rs) is the reference.
21
+
22
+ ### Installation
23
+
24
+ ```bash
25
+ bundle add rolldown
26
+ ```
27
+
28
+ Anywhere a precompiled gem is not published, the gem builds from source and needs the [Rust toolchain](https://rustup.rs) at 1.96 or newer.
29
+
30
+ ### Usage
31
+
32
+ The options follow [Rolldown's JavaScript API](https://rolldown.rs/reference/config-options), so a `rolldown.config.js` ports across as it reads.
33
+
34
+ ```ruby
35
+ result = Rolldown.build(
36
+ input: "src/main.js",
37
+ output: {
38
+ file: "bundle.js"
39
+ }
40
+ )
41
+
42
+ result.entry.code
43
+ ```
44
+
45
+ Everything comes back in memory. `write` puts it on disk, chunks and source maps together, creating the directory if it is missing.
46
+
47
+ ```ruby
48
+ result = Rolldown.build(
49
+ input: "app/javascript/application.js",
50
+ output: {
51
+ dir: "app/assets/builds",
52
+ format: "esm",
53
+ sourcemap: true,
54
+ minify: true
55
+ }
56
+ )
57
+
58
+ result.write
59
+ #=> ["app/assets/builds/application.js", "app/assets/builds/application.js.map"]
60
+ ```
61
+
62
+ `write` goes to `output.dir`, or to whatever directory `output.file` names, and takes an argument to go somewhere else. `output.dir` also decides what the source map's relative paths look like, so it is worth setting even when writing elsewhere.
63
+
64
+ Writing happens in Ruby. Rolldown can do it, but it hands the whole bundle back either way, so writing from Rust measured slower while giving the caller less say over where files land.
65
+
66
+ #### Entry points
67
+
68
+ An entry point is a string, a list, or a hash of names, matching `string | string[] | Record<string, string>`.
69
+
70
+ ```ruby
71
+ Rolldown.build(input: "src/main.js")
72
+ Rolldown.build(input: ["src/main.js", "src/admin.js"])
73
+ Rolldown.build(input: { app: "src/main.js", admin: "src/admin.js" })
74
+ ```
75
+
76
+ #### Bundling something that is not a file
77
+
78
+ `modules` hands the bundler sources it holds in memory, keyed by whatever name you want to import them under.
79
+
80
+ ```ruby
81
+ Rolldown.build(
82
+ input: "app:entry",
83
+ modules: {
84
+ "app:entry" => %(import { card } from "app:users/card"\ncard()),
85
+ "app:users/card" => %(export function card() { ... })
86
+ }
87
+ )
88
+ ```
89
+
90
+ They mix freely with what is on disk. A module in memory can import an npm package or a relative file, and a file on disk can import a module in memory. A relative import out of a module in memory resolves against that module's own name, so give it a path-shaped one when it needs to reach real files next to it.
91
+
92
+ This exists so a generator can transform sources in Ruby first and bundle the result without writing anything out. There are no plugins, and no Ruby runs while the bundle does.
93
+
94
+ #### What comes back
95
+
96
+ ```ruby
97
+ result.chunks # every chunk, each with filename, name, code, map, imports, exports and module_ids
98
+ result.assets # source maps and anything else emitted alongside
99
+ result.entry # the first chunk that is an entry point
100
+ result.warnings # diagnostics that did not stop the build
101
+ result.errors # diagnostics that did
102
+ result.failed?
103
+ ```
104
+
105
+ A build that produces nothing usable raises `Rolldown::BuildError` carrying what went wrong. Pass `strict: true` to raise on warnings too.
106
+
107
+ #### Bundling, not installing
108
+
109
+ Bare imports resolve with no plugin and no configuration whenever the files are on disk. Putting them there is a package manager, and this gem is not one. An app whose JavaScript is its own code plus a few vendored libraries needs nothing else.
110
+
111
+ #### Which options are bound
112
+
113
+ Of the JavaScript API's 22 input options and 49 output options, these are bound so far.
114
+
115
+ At the top level, `input`, `cwd`, `external`, `platform`, `treeshake`, `shim_missing_exports`, `module_types` and `modules`, plus `transform` for `define`.
116
+
117
+ Under `output`, `dir`, `file`, `format`, `name`, `exports`, `sourcemap`, `minify`, `banner`, `footer`, `intro`, `outro`, `entry_file_names`, `chunk_file_names`, `asset_file_names`, `keep_names`, `legal_comments` and `es_module`.
118
+
119
+ Names follow the JavaScript spelling in snake_case, so `entryFileNames` is `entry_file_names`. Where JavaScript and Rust disagree, JavaScript wins, and `define` sits under `transform` for the same reason.
120
+
121
+ #### What cannot cross
122
+
123
+ Options that take a JavaScript function in the JavaScript API have nowhere to go in Ruby. `plugins`, `on_log`, `manual_chunks` and `sourcemap_path_transform` are refused by name, and anything else Rolldown does not recognise is refused too.
124
+
125
+ Watch mode, hot module replacement and the dev server are not bound.
126
+
127
+ ### Development
128
+
129
+ The gem is a C extension over a Rust crate. `rust/` builds a static library and generates the C header with [cbindgen](https://github.com/mozilla/cbindgen), `ext/rolldown/` wraps it, and `lib/` is the Ruby API over that.
130
+
131
+ ```bash
132
+ bin/setup
133
+ bundle exec rake
134
+ ```
135
+
136
+ `sig/` is generated from the `#:` annotations next to the code. Regenerate it with `rake rbs` after changing a signature, and CI checks that it matches.
137
+
138
+ ### Acknowledgements
139
+
140
+ [Rolldown](https://rolldown.rs) is maintained at [rolldown/rolldown](https://github.com/rolldown/rolldown) and is part of [VoidZero](https://voidzero.dev)'s toolchain for JavaScript. This gem only calls into it. Thank you for building these tools!
141
+
142
+ ### Contributing
143
+
144
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marcoroth/rolldown-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/marcoroth/rolldown-ruby/blob/main/CODE_OF_CONDUCT.md).
145
+
146
+ Issues with parsing, transforming or minifying itself belong [upstream](https://github.com/rolldown/rolldown/issues), since this gem does none of that. Issues with the Ruby API, the build, or the bindings belong here.
147
+
148
+ ### License
149
+
150
+ The Ruby, C, and Rust code in this gem is available under the terms of the [MIT License](https://opensource.org/licenses/MIT).
151
+
152
+ It builds against [Rolldown](https://github.com/rolldown/rolldown), which is MIT licensed and carries some MIT code of its own. A copy of both travels with the gem in [`licenses/`](licenses).
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "fileutils"
5
+
6
+ ext_dir = __dir__
7
+ root_dir = File.expand_path("../..", ext_dir)
8
+
9
+ rust_dir = File.join(root_dir, "rust")
10
+
11
+ unless File.exist?(File.join(rust_dir, "Cargo.toml"))
12
+ abort <<~MESSAGE
13
+
14
+ ERROR: Rust sources not found at #{rust_dir}.
15
+
16
+ MESSAGE
17
+ end
18
+
19
+ unless system("cargo --version > /dev/null 2>&1")
20
+ abort <<~MESSAGE
21
+
22
+ ERROR: Rust toolchain not found.
23
+
24
+ rolldown requires the Rust toolchain to compile from source.
25
+
26
+ Install Rust: https://rustup.rs
27
+
28
+ MESSAGE
29
+ end
30
+
31
+ RUST_TARGETS = {
32
+ "aarch64-linux-gnu" => "aarch64-unknown-linux-gnu",
33
+ "aarch64-linux-musl" => "aarch64-unknown-linux-musl",
34
+ "arm-linux-gnu" => "armv7-unknown-linux-gnueabihf",
35
+ "arm-linux-musl" => "armv7-unknown-linux-musleabihf",
36
+ "arm64-darwin" => "aarch64-apple-darwin",
37
+ "x86_64-darwin" => "x86_64-apple-darwin",
38
+ "x86_64-linux-gnu" => "x86_64-unknown-linux-gnu",
39
+ "x86_64-linux-musl" => "x86_64-unknown-linux-musl",
40
+ "x86-linux-gnu" => "i686-unknown-linux-gnu",
41
+ "x86-linux-musl" => "i686-unknown-linux-musl",
42
+ }.freeze
43
+
44
+ cross_compiling = ENV.key?("RUBY_CC_VERSION")
45
+ target_platform = ENV.fetch("CARGO_BUILD_TARGET", nil)
46
+
47
+ if cross_compiling && target_platform.nil?
48
+ rcd_platform = ENV.fetch("RCD_PLATFORM", "")
49
+ target_platform = RUST_TARGETS[rcd_platform]
50
+
51
+ if target_platform.nil?
52
+ ruby_platform = RbConfig::CONFIG["arch"]
53
+ target_platform = RUST_TARGETS.values.find { |target| ruby_platform.include?(target.split("-").first) }
54
+ end
55
+ end
56
+
57
+ header_path = File.join(ext_dir, "include", "rolldown.h")
58
+
59
+ FileUtils.mkdir_p(File.dirname(header_path))
60
+
61
+ target_dir = File.join(rust_dir, "target")
62
+
63
+ if target_platform
64
+ puts "rolldown: Cross-compiling Rust for target: #{target_platform}"
65
+
66
+ system("rustup target add #{target_platform}") || warn("rolldown: Failed to add Rust target #{target_platform}")
67
+
68
+ cargo_args = "--release --locked --target #{target_platform}"
69
+ lib_dir = File.join(target_dir, target_platform, "release")
70
+ else
71
+ puts "rolldown: Compiling Rust library for native platform..."
72
+
73
+ cargo_args = "--release --locked"
74
+ lib_dir = File.join(target_dir, "release")
75
+ end
76
+
77
+ unless system("cd #{rust_dir} && cargo build #{cargo_args}")
78
+ abort "ERROR: Failed to compile rolldown from Rust source."
79
+ end
80
+
81
+ unless File.exist?(header_path)
82
+ abort "ERROR: cbindgen did not generate #{header_path}. Try `cargo clean` in #{rust_dir} and reinstall."
83
+ end
84
+
85
+ static_lib = File.join(lib_dir, "librolldown_ffi.a")
86
+
87
+ developing = File.exist?(File.join(root_dir, ".git"))
88
+
89
+ if File.exist?(static_lib) && !developing
90
+ vendored = File.join(ext_dir, "librolldown_ffi.a")
91
+
92
+ FileUtils.cp(static_lib, vendored)
93
+ FileUtils.rm_rf(target_dir)
94
+
95
+ puts "rolldown: Static library vendored at #{vendored}, Rust build directory removed"
96
+
97
+ $LDFLAGS << " #{vendored}"
98
+ elsif File.exist?(static_lib)
99
+ puts "rolldown: Static library found at #{static_lib}"
100
+
101
+ $LDFLAGS << " #{static_lib}"
102
+ else
103
+ host_os = target_platform || RbConfig::CONFIG["host_os"]
104
+
105
+ lib_name = case host_os
106
+ when /darwin/ then "librolldown_ffi.dylib"
107
+ when /mingw|mswin|windows/ then "rolldown_ffi.dll"
108
+ else "librolldown_ffi.so"
109
+ end
110
+
111
+ lib_path = File.join(lib_dir, lib_name)
112
+
113
+ abort "ERROR: Shared library not found at #{lib_path}" unless File.exist?(lib_path)
114
+
115
+ puts "rolldown: Shared library found at #{lib_path} (dynamic)"
116
+
117
+ $LDFLAGS << " -L#{lib_dir} -lrolldown_ffi"
118
+ $LDFLAGS << " -Wl,-rpath,#{lib_dir}" if RbConfig::CONFIG["host_os"].match?(/darwin|linux/)
119
+ end
120
+
121
+ $CFLAGS << " -I#{ext_dir}"
122
+
123
+ create_makefile("rolldown/rolldown")
@@ -0,0 +1,54 @@
1
+ /* Generated by cbindgen, do not edit manually */
2
+
3
+ #include <stdbool.h>
4
+ #include <stdint.h>
5
+ #include <stddef.h>
6
+
7
+ #ifndef ROLLDOWN_H
8
+ #define ROLLDOWN_H
9
+
10
+ typedef enum RolldownErrorCode {
11
+ ROLLDOWN_ERROR_CODE_NONE = 0,
12
+ ROLLDOWN_ERROR_CODE_OPTION,
13
+ ROLLDOWN_ERROR_CODE_ENCODING,
14
+ ROLLDOWN_ERROR_CODE_BUILD,
15
+ ROLLDOWN_ERROR_CODE_IO,
16
+ ROLLDOWN_ERROR_CODE_INTERNAL,
17
+ ROLLDOWN_ERROR_CODE_PANIC,
18
+ } RolldownErrorCode;
19
+
20
+ typedef struct RolldownResult {
21
+ char *value;
22
+ uintptr_t value_len;
23
+ char *error;
24
+ enum RolldownErrorCode code;
25
+ } RolldownResult;
26
+
27
+ /**
28
+ * # Safety
29
+ *
30
+ * `options_json` must be a valid, nul-terminated UTF-8 string.
31
+ */
32
+ struct RolldownResult rolldown_build(const char *options_json);
33
+
34
+ char *rolldown_version(void);
35
+
36
+ char *rolldown_rolldown_version(void);
37
+
38
+ /**
39
+ * # Safety
40
+ *
41
+ * `value` must be a pointer this library returned, and must not be used afterwards.
42
+ */
43
+ void rolldown_string_free(char *value);
44
+
45
+ /**
46
+ * # Safety
47
+ *
48
+ * `result` must be one this library returned, and must not be used afterwards.
49
+ */
50
+ void rolldown_result_free(struct RolldownResult result);
51
+
52
+ struct RolldownResult rolldown_panic_for_test(void);
53
+
54
+ #endif /* ROLLDOWN_H */
@@ -0,0 +1,130 @@
1
+ #include <ruby.h>
2
+ #include <ruby/encoding.h>
3
+ #include <ruby/thread.h>
4
+ #include "include/rolldown.h"
5
+
6
+ static VALUE rb_mRolldown;
7
+ static VALUE rb_mBackend;
8
+ static VALUE rb_eError;
9
+ static VALUE rb_eOptionError;
10
+ static VALUE rb_eRolldownEncodingError;
11
+ static VALUE rb_eBuildError;
12
+ static VALUE rb_eRolldownIOError;
13
+ static VALUE rb_eInternalError;
14
+ static VALUE rb_ePanicError;
15
+
16
+ typedef struct RolldownResult (*rolldown_function)(const char *);
17
+
18
+ struct call_arguments {
19
+ rolldown_function function;
20
+ const char *options;
21
+ struct RolldownResult result;
22
+ };
23
+
24
+ static VALUE make_utf8_string(const char *cstring) {
25
+ return rb_enc_str_new_cstr(cstring, rb_utf8_encoding());
26
+ }
27
+
28
+ static VALUE take_utf8_string(char *cstring) {
29
+ if (!cstring) return Qnil;
30
+
31
+ VALUE string = make_utf8_string(cstring);
32
+ rolldown_string_free(cstring);
33
+
34
+ return string;
35
+ }
36
+
37
+ static VALUE error_class_for(enum RolldownErrorCode code) {
38
+ switch (code) {
39
+ case ROLLDOWN_ERROR_CODE_OPTION: return rb_eOptionError;
40
+ case ROLLDOWN_ERROR_CODE_ENCODING: return rb_eRolldownEncodingError;
41
+ case ROLLDOWN_ERROR_CODE_BUILD: return rb_eBuildError;
42
+ case ROLLDOWN_ERROR_CODE_IO: return rb_eRolldownIOError;
43
+ case ROLLDOWN_ERROR_CODE_PANIC: return rb_ePanicError;
44
+ default: return rb_eInternalError;
45
+ }
46
+ }
47
+
48
+ static VALUE unwrap(struct RolldownResult result) {
49
+ if (result.error) {
50
+ VALUE message = make_utf8_string(result.error);
51
+ VALUE error_class = error_class_for(result.code);
52
+
53
+ rolldown_result_free(result);
54
+
55
+ rb_raise(error_class, "%s", StringValueCStr(message));
56
+ }
57
+
58
+ if (!result.value) {
59
+ rolldown_result_free(result);
60
+
61
+ rb_raise(rb_eInternalError, "rolldown returned no result");
62
+ }
63
+
64
+ VALUE value = rb_enc_str_new(result.value, (long) result.value_len, rb_utf8_encoding());
65
+
66
+ rolldown_result_free(result);
67
+
68
+ return value;
69
+ }
70
+
71
+ static void *without_gvl(void *data) {
72
+ struct call_arguments *arguments = (struct call_arguments *) data;
73
+
74
+ arguments->result = arguments->function(arguments->options);
75
+
76
+ return NULL;
77
+ }
78
+
79
+ static VALUE call(rolldown_function function, VALUE options) {
80
+ struct call_arguments arguments;
81
+
82
+ arguments.function = function;
83
+ arguments.options = StringValueCStr(options);
84
+
85
+ rb_thread_call_without_gvl(without_gvl, &arguments, NULL, NULL);
86
+
87
+ return unwrap(arguments.result);
88
+ }
89
+
90
+ static VALUE rb_build(VALUE self, VALUE options) {
91
+ (void) self;
92
+
93
+ return call(rolldown_build, options);
94
+ }
95
+
96
+ static VALUE rb_panic_for_test(VALUE self) {
97
+ (void) self;
98
+
99
+ return unwrap(rolldown_panic_for_test());
100
+ }
101
+
102
+ static VALUE rb_native_version(VALUE self) {
103
+ (void) self;
104
+
105
+ return take_utf8_string(rolldown_version());
106
+ }
107
+
108
+ static VALUE rb_rolldown_version(VALUE self) {
109
+ (void) self;
110
+
111
+ return take_utf8_string(rolldown_rolldown_version());
112
+ }
113
+
114
+ void Init_rolldown(void) {
115
+ rb_mRolldown = rb_define_module("Rolldown");
116
+ rb_mBackend = rb_define_module_under(rb_mRolldown, "Backend");
117
+
118
+ rb_eError = rb_define_class_under(rb_mRolldown, "Error", rb_eStandardError);
119
+ rb_eOptionError = rb_define_class_under(rb_mRolldown, "OptionError", rb_eError);
120
+ rb_eRolldownEncodingError = rb_define_class_under(rb_mRolldown, "EncodingError", rb_eError);
121
+ rb_eBuildError = rb_define_class_under(rb_mRolldown, "BuildError", rb_eError);
122
+ rb_eRolldownIOError = rb_define_class_under(rb_mRolldown, "IOError", rb_eError);
123
+ rb_eInternalError = rb_define_class_under(rb_mRolldown, "InternalError", rb_eError);
124
+ rb_ePanicError = rb_define_class_under(rb_mRolldown, "PanicError", rb_eInternalError);
125
+
126
+ rb_define_singleton_method(rb_mBackend, "build", rb_build, 1);
127
+ rb_define_singleton_method(rb_mBackend, "panic_for_test", rb_panic_for_test, 0);
128
+ rb_define_singleton_method(rb_mBackend, "version", rb_native_version, 0);
129
+ rb_define_singleton_method(rb_mBackend, "rolldown_version", rb_rolldown_version, 0);
130
+ }
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rolldown
4
+ class Asset
5
+ attr_reader :filename #: String
6
+ attr_reader :names #: Array[String]
7
+ attr_reader :source #: String?
8
+
9
+ #: (Hash[String, untyped]) -> Rolldown::Asset
10
+ def self.from_hash(hash)
11
+ new(filename: hash.fetch("filename"), names: hash.fetch("names"), source: hash["source"])
12
+ end
13
+
14
+ #: (filename: String, names: Array[String], source: String?) -> void
15
+ def initialize(filename:, names:, source:)
16
+ @filename = filename.freeze
17
+ @names = names.freeze
18
+ @source = source&.freeze
19
+
20
+ freeze
21
+ end
22
+
23
+ #: () -> String
24
+ def to_s
25
+ source.to_s
26
+ end
27
+
28
+ #: () -> String
29
+ def inspect
30
+ "#<#{self.class.name} #{filename.inspect}#{" #{source.bytesize} bytes" if source}>"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rolldown
4
+ module Backend
5
+ module Unavailable
6
+ #: (String) -> String
7
+ def build(_options_json)
8
+ unavailable(__method__)
9
+ end
10
+
11
+ #: () -> String
12
+ def panic_for_test
13
+ unavailable(__method__)
14
+ end
15
+
16
+ #: () -> String
17
+ def version
18
+ unavailable(__method__)
19
+ end
20
+
21
+ #: () -> String
22
+ def rolldown_version
23
+ unavailable(__method__)
24
+ end
25
+
26
+ private
27
+
28
+ #: (Symbol?) -> bot
29
+ def unavailable(name)
30
+ raise NotImplementedError, "Rolldown::Backend.#{name} is defined by the native extension, which did not load"
31
+ end
32
+ end
33
+
34
+ extend Unavailable
35
+ end
36
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "pathname"
5
+ require "fileutils"
6
+
7
+ module Rolldown
8
+ class BuildResult
9
+ attr_reader :chunks #: Array[Rolldown::Chunk]
10
+ attr_reader :assets #: Array[Rolldown::Asset]
11
+ attr_reader :warnings #: Array[Rolldown::Diagnostic]
12
+ attr_reader :errors #: Array[Rolldown::Diagnostic]
13
+ attr_reader :dir #: String?
14
+ attr_reader :cwd #: String?
15
+
16
+ #: (String, ?String?, ?String?) -> Rolldown::BuildResult
17
+ def self.from_json(payload, dir = nil, cwd = nil)
18
+ parsed = JSON.parse(payload)
19
+
20
+ new(
21
+ dir: dir,
22
+ cwd: cwd,
23
+ chunks: parsed.fetch("chunks").map { |chunk| Chunk.from_hash(chunk) },
24
+ assets: parsed.fetch("assets").map { |asset| Asset.from_hash(asset) },
25
+ warnings: parsed.fetch("warnings").map { |warning| Diagnostic.from_hash(warning) },
26
+ errors: parsed.fetch("errors").map { |error| Diagnostic.from_hash(error) },
27
+ failed: parsed.fetch("failed")
28
+ )
29
+ end #: String?
30
+
31
+ #: (chunks: Array[Rolldown::Chunk], assets: Array[Rolldown::Asset], warnings: Array[Rolldown::Diagnostic], errors: Array[Rolldown::Diagnostic], failed: bool, ?dir: String?, ?cwd: String?) -> void
32
+ def initialize(chunks:, assets:, warnings:, errors:, failed:, dir: nil, cwd: nil)
33
+ @dir = dir
34
+ @cwd = cwd
35
+ @chunks = chunks.freeze
36
+ @assets = assets.freeze
37
+ @warnings = warnings.freeze
38
+ @errors = errors.freeze
39
+ @failed = failed
40
+
41
+ freeze
42
+ end
43
+
44
+ #: () -> bool
45
+ def failed?
46
+ @failed
47
+ end
48
+
49
+ #: () -> bool
50
+ def errors?
51
+ !errors.empty?
52
+ end
53
+
54
+ #: () -> bool
55
+ def warnings?
56
+ !warnings.empty?
57
+ end
58
+
59
+ #: (?String?) -> Array[String]
60
+ def write(into = dir)
61
+ raise IOError, "no directory to write to, pass one or set output.dir or output.file" unless into
62
+
63
+ root = cwd ? File.expand_path(into, cwd) : into
64
+
65
+ FileUtils.mkdir_p(root)
66
+
67
+ (chunks + assets).map do |file|
68
+ path = Pathname.new(root).join(file.filename).cleanpath.to_s
69
+
70
+ FileUtils.mkdir_p(File.dirname(path))
71
+ File.write(path, file.to_s)
72
+
73
+ path
74
+ end
75
+ end
76
+
77
+ #: () -> Rolldown::Chunk?
78
+ def entry
79
+ chunks.find(&:entry?)
80
+ end
81
+
82
+ #: (?strict: bool) -> Rolldown::BuildResult
83
+ def validate!(strict: false)
84
+ raise BuildError, errors.map(&:message).join("\n\n") if failed? || errors?
85
+ raise BuildError, warnings.map(&:message).join("\n\n") if strict && warnings?
86
+
87
+ self
88
+ end
89
+
90
+ #: () -> String
91
+ def to_s
92
+ chunks.map(&:code).join("\n")
93
+ end
94
+
95
+ #: () -> String
96
+ def inspect
97
+ parts = ["chunks=#{chunks.length}"]
98
+ parts << "assets=#{assets.length}" unless assets.empty?
99
+ parts << "warnings=#{warnings.length}" unless warnings.empty?
100
+ parts << "errors=#{errors.length}" unless errors.empty?
101
+ parts << "failed" if failed?
102
+
103
+ "#<#{self.class.name} #{parts.join(" ")}>"
104
+ end
105
+ end
106
+ end