{
153 | let len = s.len() as i64;
154 |
155 | let index = if index < 0 { index + len } else { index };
156 |
157 | if index < 0 || index > len {
158 | return Err(Error::new_with_reason(
159 | MagicStringErrorType::MagicStringOutOfRangeError,
160 | "index out of range",
161 | ));
162 | }
163 |
164 | Ok(index as usize)
165 | }
166 |
--------------------------------------------------------------------------------
/core/tests/move.rs:
--------------------------------------------------------------------------------
1 | #[cfg(test)]
2 | mod _move {
3 | use magic_string::{MagicString, OverwriteOptions, Result};
4 |
5 | #[test]
6 | fn should_move_from_start() -> Result {
7 | let mut s = MagicString::new("abcdefghijkl");
8 |
9 | s._move(0, 3, 6)?;
10 | assert_eq!(s.to_string(), "defabcghijkl");
11 | Ok(())
12 | }
13 |
14 | #[test]
15 | fn should_move_to_start() -> Result {
16 | let mut s = MagicString::new("abcdefghijkl");
17 |
18 | s._move(3, 6, 0)?;
19 |
20 | assert_eq!(s.to_string(), "defabcghijkl");
21 | Ok(())
22 | }
23 |
24 | #[test]
25 | fn should_move_from_end() -> Result {
26 | let mut s = MagicString::new("abcdefghijkl");
27 |
28 | s._move(9, 12, 3)?;
29 |
30 | assert_eq!(s.to_string(), "abcjkldefghi");
31 | Ok(())
32 | }
33 | #[test]
34 | fn should_move_to_end() -> Result {
35 | let mut s = MagicString::new("abcdefghijkl");
36 |
37 | s._move(3, 6, 12)?;
38 |
39 | assert_eq!(s.to_string(), "abcghijkldef");
40 | Ok(())
41 | }
42 |
43 | #[test]
44 | fn should_move_and_remove() -> Result {
45 | let mut s = MagicString::new("abcdefghijkl");
46 |
47 | s._move(3, 6, 12)?;
48 | s._move(3, 5, 0)?;
49 |
50 | assert_eq!(s.to_string(), "deabcghijklf");
51 |
52 | Ok(())
53 | }
54 |
55 | #[test]
56 | fn should_move_after_insert() -> Result {
57 | let mut s = MagicString::new("abcdefghijk");
58 |
59 | s.prepend("xyz")?;
60 | s.append("mn")?;
61 | s.prepend_left(4, "A")?;
62 | s.append_left(4, "B")?;
63 | s.prepend_right(4, "C")?;
64 | s.append_right(4, "D")?;
65 | s._move(0, 3, 6)?;
66 | assert_eq!(s.to_string(), "xyzdABCDefabcghijkmn");
67 | Ok(())
68 | }
69 |
70 | #[test]
71 | fn should_ignores_redundant_move() -> Result {
72 | let mut s = MagicString::new("abcdefghijkl");
73 | s.prepend_right(9, "X")?;
74 | s._move(9, 12, 6)?;
75 | s.append_left(12, "Y")?;
76 | s._move(6, 9, 12)?; // this is redundant – [6,9] is already after [9,12]
77 |
78 | assert_eq!(s.to_string(), "abcdefXjklYghi");
79 |
80 | Ok(())
81 | }
82 |
83 | #[test]
84 | fn should_move_content_to_middle() -> Result {
85 | let mut s = MagicString::new("abcdefghijkl");
86 | s._move(3, 6, 9)?;
87 |
88 | assert_eq!(s.to_string(), "abcghidefjkl");
89 | Ok(())
90 | }
91 |
92 | #[test]
93 | fn should_handles_multiple_moves_of_same_snippet() -> Result {
94 | let mut s = MagicString::new("abcdefghijkl");
95 | s._move(0, 3, 6)?;
96 | assert_eq!(s.to_string(), "defabcghijkl");
97 |
98 | s._move(0, 3, 9)?;
99 | assert_eq!(s.to_string(), "defghiabcjkl");
100 |
101 | Ok(())
102 | }
103 | #[test]
104 | fn should_handles_moves_of_adjacent_snippets() -> Result {
105 | let mut s = MagicString::new("abcdefghijkl");
106 | s._move(0, 2, 6)?;
107 | assert_eq!(s.to_string(), "cdefabghijkl");
108 |
109 | s._move(2, 4, 6)?;
110 | assert_eq!(s.to_string(), "efabcdghijkl");
111 |
112 | Ok(())
113 | }
114 | #[test]
115 | fn should_handles_moves_to_same_index() -> Result {
116 | let mut s = MagicString::new("abcdefghijkl");
117 | s._move(0, 2, 6)?._move(3, 5, 6)?;
118 | assert_eq!(s.to_string(), "cfabdeghijkl");
119 |
120 | Ok(())
121 | }
122 | #[test]
123 | fn should_allows_edits_of_moved_content() -> Result {
124 | let mut s = MagicString::new("abcdefghijkl");
125 | s._move(3, 6, 9)?;
126 | s.overwrite(3, 6, "DEF", OverwriteOptions::default())?;
127 | assert_eq!(s.to_string(), "abcghiDEFjkl");
128 |
129 | let mut s = MagicString::new("abcdefghijkl");
130 |
131 | s._move(3, 6, 9)?;
132 | s.overwrite(4, 5, "E", OverwriteOptions::default())?;
133 | assert_eq!(s.to_string(), "abcghidEfjkl");
134 | Ok(())
135 | }
136 | // #[test]
137 | // fn should_move_follows_inserts() -> Result {
138 | // let mut s = MagicString::new("abcdefghijkl");
139 | // s._move(3, 6, 9)?;
140 |
141 | // assert_eq!(s.to_string(), "abcghidefjkl");
142 | // Ok(())
143 | // }
144 | #[test]
145 | fn should_moves_content_inserted_at_end_of_range() -> Result {
146 | let mut s = MagicString::new("abcdefghijkl");
147 | s.append_left(6, "X")?._move(3, 6, 9)?;
148 |
149 | assert_eq!(s.to_string(), "abcghidefXjkl");
150 |
151 | Ok(())
152 | }
153 | #[test]
154 | fn should_returns_this() -> Result {
155 | let mut s = MagicString::new("abcdefghijkl");
156 |
157 | let result = s._move(3, 6, 9)?;
158 | let result_ptr = result as *mut _;
159 | let s_ptr = &s as *const _;
160 |
161 | assert_eq!(s_ptr, result_ptr);
162 | Ok(())
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/benchmark/bench.ts:
--------------------------------------------------------------------------------
1 | import b from 'benny'
2 | import MagicString from 'magic-string'
3 |
4 | import { MagicString as MagicStringRust } from '../node'
5 |
6 | const BANNER = `/*!
7 | * Vue.js v2.6.14
8 | * (c) 2014-2021 Evan You
9 | * Released under the MIT License.
10 | */
11 | `
12 |
13 | const EXPORT_STATEMENT = `export default foo`
14 |
15 | b.suite(
16 | 'overwrite',
17 | b.add('MagicString', () => {
18 | const m = new MagicString(`export const foo = 'bar'`)
19 | m.overwrite(13, 16, "bar")
20 | }),
21 | b.add('MagicStringRust', () => {
22 | const m = new MagicStringRust(`export const foo = 'bar'`)
23 | m.overwrite(13, 16, "bar")
24 | }),
25 | b.cycle(),
26 | b.complete(),
27 | )
28 |
29 | b.suite(
30 | 'prepend|append',
31 | b.add('MagicString', () => {
32 | const m = new MagicString(`export const foo = 'bar'`)
33 | m.prepend(BANNER)
34 | m.append(EXPORT_STATEMENT)
35 | }),
36 | b.add('MagicStringRust', () => {
37 | const m = new MagicStringRust(`export const foo = 'bar'`)
38 | m.prepend(BANNER)
39 | m.append(EXPORT_STATEMENT)
40 | }),
41 | b.cycle(),
42 | b.complete(),
43 | )
44 |
45 | b.suite(
46 | 'add banner#toString',
47 | b.add('MagicString', () => {
48 | const m = new MagicString(`export const foo = 'bar'`)
49 | m.prepend(BANNER)
50 | m.toString()
51 | }),
52 | b.add('MagicStringRust', () => {
53 | const m = new MagicStringRust(`export const foo = 'bar'`)
54 | m.prepend(BANNER)
55 | m.toString()
56 | }),
57 | b.cycle(),
58 | b.complete(),
59 | )
60 |
61 | b.suite(
62 | 'add banner#generateDecodedMap',
63 | b.add('MagicString', () => {
64 | const m = new MagicString(`export const foo = 'bar'`)
65 | m.prepend(BANNER)
66 | m.generateDecodedMap()
67 | }),
68 | b.add('MagicStringRust', () => {
69 | const m = new MagicStringRust(`export const foo = 'bar'`)
70 | m.prepend(BANNER)
71 | m.generateDecodedMap()
72 | }),
73 | b.cycle(),
74 | b.complete(),
75 | )
76 |
77 | b.suite(
78 | 'add banner#generateMapHires',
79 | b.add('MagicString', () => {
80 | const m = new MagicString(`export const foo = 'bar'`)
81 | m.prepend(BANNER)
82 | m.generateMap({
83 | hires: true
84 | })
85 | }),
86 | b.add('MagicStringRust', () => {
87 | const m = new MagicStringRust(`export const foo = 'bar'`)
88 | m.prepend(BANNER)
89 | m.generateMap({
90 | hires: true
91 | }).toMap()
92 | }),
93 | b.cycle(),
94 | b.complete(),
95 | )
96 |
97 | b.suite(
98 | 'add banner#generateMap',
99 | b.add('MagicString', () => {
100 | const m = new MagicString(`export const foo = 'bar'`)
101 | m.prepend(BANNER)
102 | m.generateMap()
103 | }),
104 | b.add('MagicStringRust', () => {
105 | const m = new MagicStringRust(`export const foo = 'bar'`)
106 | m.prepend(BANNER)
107 | m.generateMap().toMap()
108 | }),
109 | b.cycle(),
110 | b.complete(),
111 | )
112 |
113 | b.suite(
114 | 'add banner#generateMap.toString',
115 | b.add('MagicString', () => {
116 | const m = new MagicString(`export const foo = 'bar'`)
117 | m.prepend(BANNER)
118 | m.generateMap().toString()
119 | }),
120 | b.add('MagicStringRust', () => {
121 | const m = new MagicStringRust(`export const foo = 'bar'`)
122 | m.prepend(BANNER)
123 | m.generateMap().toString()
124 | }),
125 | b.cycle(),
126 | b.complete(),
127 | )
128 |
129 | b.suite(
130 | 'add banner#generateMapHires.toString',
131 | b.add('MagicString', () => {
132 | const m = new MagicString(`export const foo = 'bar'`)
133 | m.prepend(BANNER)
134 | m.generateMap({
135 | hires: true
136 | }).toString()
137 | }),
138 | b.add('MagicStringRust', () => {
139 | const m = new MagicStringRust(`export const foo = 'bar'`)
140 | m.prepend(BANNER)
141 | m.generateMap({
142 | hires: true
143 | }).toString()
144 | }),
145 | b.cycle(),
146 | b.complete(),
147 | )
148 |
149 | b.suite(
150 | 'add banner#generateMap.toUrl',
151 | b.add('MagicString', () => {
152 | const m = new MagicString(`export const foo = 'bar'`)
153 | m.prepend(BANNER)
154 | m.generateMap().toUrl()
155 | }),
156 | b.add('MagicStringRust', () => {
157 | const m = new MagicStringRust(`export const foo = 'bar'`)
158 | m.prepend(BANNER)
159 | m.generateMap().toUrl()
160 | }),
161 | b.cycle(),
162 | b.complete(),
163 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | magic-string-rs
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | MagicString port for Node and modern browsers, also, for rust, of course.
13 |
14 |
15 |
16 |
17 | ## 🔧 Installation
18 |
19 | ### Rust
20 |
21 | Add it as a dependency in a Cargo project.
22 |
23 | ```toml
24 | # Cargo.toml
25 |
26 | [dependency]
27 | magic_string = "x.x.x"
28 | ```
29 |
30 | ### Node
31 |
32 | ```bash
33 | $ npm install @napi-rs/magic-string
34 | ```
35 |
36 | Note: Web-Assembly is currently not supported, but it's on the plan.
37 |
38 | ## Performance
39 |
40 | ### Hardware info
41 |
42 | ```
43 | Model Name: MacBook Pro
44 | Model Identifier: MacBookPro17,1
45 | Chip: Apple M1
46 | Total Number of Cores: 8 (4 performance and 4 efficiency)
47 | Memory: 16 GB
48 | ```
49 |
50 | ### Benchmark
51 |
52 | ```
53 | Running "overwrite" suite...
54 | Progress: 100%
55 |
56 | MagicString:
57 | 238 584 ops/s, ±0.34% | slowest, 50.7% slower
58 |
59 | MagicStringRust:
60 | 483 950 ops/s, ±2.13% | fastest
61 |
62 | Finished 2 cases!
63 | Fastest: MagicStringRust
64 | Slowest: MagicString
65 |
66 | Running "prepend|append" suite...
67 | Progress: 100%
68 |
69 | MagicString:
70 | 290 244 ops/s, ±1.35% | slowest, 48.35% slower
71 |
72 | MagicStringRust:
73 | 561 981 ops/s, ±6.71% | fastest
74 |
75 | Finished 2 cases!
76 | Fastest: MagicStringRust
77 | Slowest: MagicString
78 |
79 | Running "add banner#toString" suite...
80 | Progress: 100%
81 |
82 | MagicString:
83 | 301 467 ops/s, ±0.29% | slowest, 37.66% slower
84 |
85 | MagicStringRust:
86 | 483 586 ops/s, ±5.50% | fastest
87 |
88 | Finished 2 cases!
89 | Fastest: MagicStringRust
90 | Slowest: MagicString
91 |
92 | Running "add banner#generateDecodedMap" suite...
93 | Progress: 100%
94 |
95 | MagicString:
96 | 233 702 ops/s, ±0.76% | fastest
97 |
98 | MagicStringRust:
99 | 229 899 ops/s, ±2.68% | slowest, 1.63% slower
100 |
101 | Finished 2 cases!
102 | Fastest: MagicString
103 | Slowest: MagicStringRust
104 |
105 | Running "add banner#generateMapHires" suite...
106 | Progress: 100%
107 |
108 | MagicString:
109 | 177 783 ops/s, ±1.84% | fastest
110 |
111 | MagicStringRust:
112 | 90 780 ops/s, ±1.00% | slowest, 48.94% slower
113 |
114 | Finished 2 cases!
115 | Fastest: MagicString
116 | Slowest: MagicStringRust
117 |
118 | Running "add banner#generateMap" suite...
119 | Progress: 100%
120 |
121 | MagicString:
122 | 227 594 ops/s, ±0.68% | slowest, 0.42% slow
123 | er
124 |
125 | MagicStringRust:
126 | 228 545 ops/s, ±0.82% | fastest
127 |
128 | Finished 2 cases!
129 | Fastest: MagicStringRust
130 | Slowest: MagicString
131 |
132 | Running "add banner#generateMap.toString" suite...
133 | Progress: 100%
134 |
135 | MagicString:
136 | 201 272 ops/s, ±0.47% | slowest, 21.86% slower
137 |
138 | MagicStringRust:
139 | 257 577 ops/s, ±2.38% | fastest
140 |
141 | Finished 2 cases!
142 | Fastest: MagicStringRust
143 | Slowest: MagicString
144 |
145 | Running "add banner#generateMapHires.toString" suite...
146 | Progress: 100%
147 |
148 | MagicString:
149 | 157 685 ops/s, ±0.18% | fastest
150 |
151 | MagicStringRust:
152 | 95 510 ops/s, ±1.00% | slowest, 39.43% slower
153 |
154 | Finished 2 cases!
155 | Fastest: MagicString
156 | Slowest: MagicStringRust
157 |
158 | Running "add banner#generateMap.toUrl" suite...
159 | Progress: 100%
160 |
161 | MagicString:
162 | 182 161 ops/s, ±0.65% | slowest, 25.04% slower
163 |
164 | MagicStringRust:
165 | 243 019 ops/s, ±0.98% | fastest
166 |
167 | Finished 2 cases!
168 | Fastest: MagicStringRust
169 | Slowest: MagicString
170 | ```
171 |
172 | ## 📃 Documentation
173 |
174 | [doc.rs](https://docs.rs/magic_string/latest/magic_string)
175 |
176 | ## Supported APIs
177 |
178 | - [x] generateMap: Note that there is a huge overhead for rust for implementing the same API in Node, for more detail please refer to [this](./node/index.d.ts)
179 | - [x] generateDecodedMap
180 | - [x] toString
181 | - [x] prepend
182 | - [x] append
183 | - [x] prependLeft
184 | - [x] prependRight
185 | - [x] appendLeft
186 | - [x] appendRight
187 | - [x] overwrite
188 | - [x] trim
189 | - [x] trimStart
190 | - [x] trimEnd
191 | - [x] trimLines
192 | - [x] isEmpty
193 | - [x] remove
194 | - [ ] move
195 | - [ ] indent
196 | - [ ] addSourcemapLocation
197 | - [ ] clone
198 | - [ ] slice
199 | - [ ] snip
200 |
201 | ## Credits
202 |
203 | The original project [magic-string](https://github.com/Rich-Harris/magic-string) is really awesome, you should check it out and we made this project even furthur for better performance.
204 |
205 | ## License
206 |
207 | MIT
208 |
--------------------------------------------------------------------------------
/core/src/result.rs:
--------------------------------------------------------------------------------
1 | use std::fmt::Formatter;
2 | use std::{
3 | fmt, io, result,
4 | string::{self, FromUtf8Error},
5 | };
6 |
7 | #[derive(Debug, Clone, PartialEq)]
8 | pub enum MagicStringErrorType {
9 | IOError,
10 | UTF8Error,
11 |
12 | JSONSerializationError,
13 |
14 | VlqUnexpectedEof,
15 | VlqInvalidBase64,
16 | VlqOverflow,
17 |
18 | RegexSyntaxError,
19 | RegexCompiledTooBig,
20 | RegexUnknownError,
21 |
22 | MagicStringOutOfRangeError,
23 | MagicStringCrossChunkError,
24 | MagicStringDoubleSplitError,
25 | MagicStringDoubleEditError,
26 | MagicStringUnknownError,
27 |
28 | Default,
29 | }
30 |
31 | pub type Result = result::Result;
32 |
33 | #[derive(Debug, PartialEq)]
34 | pub struct Error {
35 | pub error_type: MagicStringErrorType,
36 | pub reason: Option,
37 | }
38 |
39 | impl Default for Error {
40 | fn default() -> Self {
41 | Self {
42 | error_type: MagicStringErrorType::Default,
43 | reason: None,
44 | }
45 | }
46 | }
47 |
48 | impl Error {
49 | pub fn new(error_type: MagicStringErrorType) -> Self {
50 | Self {
51 | error_type,
52 | reason: None,
53 | }
54 | }
55 |
56 | pub fn new_with_reason(error_type: MagicStringErrorType, reason: &str) -> Self {
57 | Self {
58 | error_type,
59 | reason: Some(String::from(reason)),
60 | }
61 | }
62 | }
63 |
64 | impl fmt::Display for Error {
65 | #[inline]
66 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
67 | if let Some(ref reason) = self.reason {
68 | write!(f, "{:?}, {}", self.error_type, reason)
69 | } else {
70 | write!(f, "{:?}", self.error_type)
71 | }
72 | }
73 | }
74 |
75 | impl From for Error {
76 | #[inline]
77 | fn from(_: io::Error) -> Self {
78 | Error::new(MagicStringErrorType::IOError)
79 | }
80 | }
81 |
82 | impl From for Error {
83 | #[inline]
84 | fn from(err: vlq::Error) -> Self {
85 | match err {
86 | vlq::Error::UnexpectedEof => Error::new(MagicStringErrorType::VlqUnexpectedEof),
87 | vlq::Error::InvalidBase64(_) => Error::new(MagicStringErrorType::VlqInvalidBase64),
88 | vlq::Error::Overflow => Error::new(MagicStringErrorType::VlqOverflow),
89 | }
90 | }
91 | }
92 |
93 | impl From for Error {
94 | #[inline]
95 | fn from(err: regex::Error) -> Self {
96 | match err {
97 | regex::Error::Syntax(_) => Error::new(MagicStringErrorType::RegexSyntaxError),
98 | regex::Error::CompiledTooBig(_) => Error::new(MagicStringErrorType::RegexCompiledTooBig),
99 | _ => Error::new(MagicStringErrorType::RegexUnknownError),
100 | }
101 | }
102 | }
103 |
104 | impl From for Error {
105 | #[inline]
106 | fn from(_: FromUtf8Error) -> Self {
107 | Error::new(MagicStringErrorType::UTF8Error)
108 | }
109 | }
110 |
111 | impl From for Error {
112 | #[inline]
113 | fn from(_: serde_json::Error) -> Self {
114 | Error::new(MagicStringErrorType::JSONSerializationError)
115 | }
116 | }
117 |
118 | #[cfg(feature = "node-api")]
119 | impl From for napi::Error {
120 | #[inline]
121 | fn from(err: Error) -> Self {
122 | let mut reason = String::from("[magic-string] ");
123 |
124 | match err.error_type {
125 | MagicStringErrorType::IOError => {
126 | reason.push_str("IO Error");
127 | }
128 | MagicStringErrorType::UTF8Error => {
129 | reason.push_str("UTF8 Encoding Error");
130 | }
131 |
132 | MagicStringErrorType::JSONSerializationError => {
133 | reason.push_str("JSON Serialization Error");
134 | }
135 |
136 | MagicStringErrorType::VlqUnexpectedEof => {
137 | reason.push_str("Vlq Unexpected Eof");
138 | }
139 | MagicStringErrorType::VlqInvalidBase64 => {
140 | reason.push_str("Vlq Unexpected Base64");
141 | }
142 | MagicStringErrorType::VlqOverflow => {
143 | reason.push_str("Vlq Overflow");
144 | }
145 |
146 | MagicStringErrorType::RegexSyntaxError => {
147 | reason.push_str("Regex Syntax Error");
148 | }
149 | MagicStringErrorType::RegexCompiledTooBig => {
150 | reason.push_str("Regex Compiled Too Big");
151 | }
152 | MagicStringErrorType::RegexUnknownError => {
153 | reason.push_str("Regex Unknown Error");
154 | }
155 |
156 | MagicStringErrorType::MagicStringOutOfRangeError => {
157 | reason.push_str("Magic String Out of Range Error");
158 | }
159 | MagicStringErrorType::MagicStringCrossChunkError => {
160 | reason.push_str("Magic String Cross Chunk Error");
161 | }
162 | MagicStringErrorType::MagicStringDoubleSplitError => {
163 | reason.push_str("Magic String Double Split Error");
164 | }
165 | MagicStringErrorType::MagicStringUnknownError => {
166 | reason.push_str("Magic encountered an unknown error, please file an issue");
167 | }
168 | MagicStringErrorType::MagicStringDoubleEditError => {
169 | reason.push_str("Magic String Double Edit Error");
170 | }
171 |
172 | MagicStringErrorType::Default => {
173 | reason.push_str(
174 | "Default Error should never been thrown to the user end, please file an issue.",
175 | );
176 | }
177 | }
178 |
179 | if let Some(r) = err.reason {
180 | reason.push_str(", ");
181 | reason.push_str(&r[..]);
182 | }
183 |
184 | napi::Error::new(napi::Status::GenericFailure, reason)
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/node/src/lib.rs:
--------------------------------------------------------------------------------
1 | extern crate napi;
2 | #[macro_use]
3 | extern crate napi_derive;
4 |
5 | use napi::bindgen_prelude::*;
6 | use napi::Result;
7 |
8 | // use magic_string::SourceMap;
9 |
10 | #[napi]
11 | pub struct MagicString(magic_string::MagicString);
12 |
13 | pub fn create_external(value: T) -> External {
14 | External::new(value)
15 | }
16 |
17 | #[napi]
18 | impl MagicString {
19 | #[napi(constructor)]
20 | pub fn new(original_str: String) -> Self {
21 | MagicString(magic_string::MagicString::new(original_str.as_str()))
22 | }
23 |
24 | #[napi]
25 | pub fn append(&mut self, input: String) -> Result<&Self> {
26 | self.0.append(input.as_str())?;
27 | Ok(self)
28 | }
29 |
30 | #[napi]
31 | pub fn prepend(&mut self, input: String) -> Result<&Self> {
32 | self.0.prepend(input.as_str())?;
33 | Ok(self)
34 | }
35 |
36 | #[napi]
37 | pub fn append_left(&mut self, index: u32, input: String) -> Result<&Self> {
38 | self.0.append_left(index, input.as_str())?;
39 | Ok(self)
40 | }
41 |
42 | #[napi]
43 | pub fn append_right(&mut self, index: u32, input: String) -> Result<&Self> {
44 | self.0.append_right(index, input.as_str())?;
45 | Ok(self)
46 | }
47 |
48 | #[napi]
49 | pub fn prepend_left(&mut self, index: u32, input: String) -> Result<&Self> {
50 | self.0.prepend_left(index, input.as_str())?;
51 | Ok(self)
52 | }
53 |
54 | #[napi]
55 | pub fn prepend_right(&mut self, index: u32, input: String) -> Result<&Self> {
56 | self.0.prepend_right(index, input.as_str())?;
57 | Ok(self)
58 | }
59 |
60 | #[napi(ts_args_type = r"
61 | start: number,
62 | end: number,
63 | content: string,
64 | options?: OverwriteOptions
65 | ")]
66 | pub fn overwrite(
67 | &mut self,
68 | start: i64,
69 | end: i64,
70 | content: String,
71 | options: magic_string::OverwriteOptions,
72 | ) -> Result<&Self> {
73 | self.0.overwrite(start, end, content.as_str(), options)?;
74 | Ok(self)
75 | }
76 |
77 | #[napi]
78 | pub fn trim(&mut self, pattern: Option) -> Result<&Self> {
79 | self.0.trim(pattern.as_deref())?;
80 | Ok(self)
81 | }
82 |
83 | #[napi]
84 | pub fn trim_start(&mut self, pattern: Option) -> Result<&Self> {
85 | self.0.trim_start(pattern.as_deref())?;
86 | Ok(self)
87 | }
88 |
89 | #[napi]
90 | pub fn trim_end(&mut self, pattern: Option) -> Result<&Self> {
91 | self.0.trim_end(pattern.as_deref())?;
92 | Ok(self)
93 | }
94 |
95 | #[napi]
96 | pub fn trim_lines(&mut self) -> Result<&Self> {
97 | self.0.trim_lines()?;
98 | Ok(self)
99 | }
100 |
101 | #[napi]
102 | pub fn remove(&mut self, start: i64, end: i64) -> Result<&Self> {
103 | self.0.remove(start, end)?;
104 | Ok(self)
105 | }
106 |
107 | #[napi]
108 | pub fn _move(&mut self, start: i64, end: i64, index: i64) -> Result<&Self> {
109 | self.0._move(start, end, index)?;
110 | Ok(self)
111 | }
112 | #[napi]
113 | pub fn is_empty(&self) -> Result {
114 | Ok(self.0.is_empty())
115 | }
116 |
117 | #[napi(
118 | ts_args_type = "options?: Partial",
119 | ts_return_type = r"{
120 | toString: () => string;
121 | toUrl: () => string;
122 | toMap: () => {
123 | version: number;
124 | file?: string;
125 | sources: string[];
126 | sourcesContent: string[];
127 | names: string[];
128 | mappings: string;
129 | sourceRoot?: string;
130 | }
131 | }"
132 | )]
133 | pub fn generate_map(&self) -> Result<()> {
134 | // only for .d.ts generation
135 | Ok(())
136 | }
137 |
138 | #[napi(skip_typescript)]
139 | pub fn to_sourcemap_string(
140 | &self,
141 | options: Option,
142 | ) -> Result {
143 | Ok(
144 | self
145 | .0
146 | .generate_map(options.unwrap_or_default())?
147 | .to_string()?,
148 | )
149 | }
150 |
151 | #[napi(skip_typescript)]
152 | pub fn to_sourcemap_url(
153 | &self,
154 | options: Option,
155 | ) -> Result {
156 | Ok(self.0.generate_map(options.unwrap_or_default())?.to_url()?)
157 | }
158 |
159 | #[napi(
160 | ts_args_type = "options?: Partial",
161 | ts_return_type = "DecodedMap"
162 | )]
163 | pub fn generate_decoded_map(
164 | &self,
165 | options: Option,
166 | ) -> Result {
167 | let decoded = self.0.generate_decoded_map(options.unwrap_or_default())?;
168 | Ok(serde_json::to_string(&decoded)?)
169 | }
170 |
171 | #[napi]
172 | #[allow(clippy::inherent_to_string)]
173 | pub fn to_string(&self) -> String {
174 | self.0.to_string()
175 | }
176 |
177 | #[napi]
178 | pub fn length(&self) -> u32 {
179 | self.0.len() as u32
180 | }
181 | }
182 |
183 | #[napi(object)]
184 | /// Only for .d.ts type generation
185 | pub struct DecodedMap {
186 | pub file: Option,
187 | pub sources: Vec