From f3cfa7f3ddf26a795e59721985ad6220439c7245 Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:49:11 +0000 Subject: [PATCH] feat(napi/parser): add `get_line_column_number` API (#7765) --- Cargo.lock | 1 + napi/parser/Cargo.toml | 1 + napi/parser/index.d.ts | 8 ++++++++ napi/parser/src/magic_string.rs | 23 ++++++++++++++++++++++- napi/parser/test/magic_string.test.ts | 6 ++++++ 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5357028946330..6f9be2bf0e1f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1834,6 +1834,7 @@ dependencies = [ "napi-derive", "oxc", "oxc_ast", + "oxc_data_structures", "oxc_napi", "rustc-hash", "self_cell", diff --git a/napi/parser/Cargo.toml b/napi/parser/Cargo.toml index a4d767d43642d..5187e4b078a64 100644 --- a/napi/parser/Cargo.toml +++ b/napi/parser/Cargo.toml @@ -23,6 +23,7 @@ doctest = false [dependencies] oxc = { workspace = true } oxc_ast = { workspace = true, features = ["serialize"] } # enable feature only +oxc_data_structures = { workspace = true } oxc_napi = { workspace = true } rustc-hash = { workspace = true } diff --git a/napi/parser/index.d.ts b/napi/parser/index.d.ts index ce9d17e1788d5..ad517dc5a072f 100644 --- a/napi/parser/index.d.ts +++ b/napi/parser/index.d.ts @@ -3,7 +3,10 @@ export * from '@oxc-project/types'; export declare class MagicString { + /** Get source text from utf8 offset. */ getSourceText(start: number, end: number): string + /** Get 0-based line and column number from utf8 offset. */ + getLineColumnNumber(offset: number): LineColumn length(): number toString(): string append(input: string): this @@ -131,6 +134,11 @@ export declare const enum ImportNameKind { Default = 'Default' } +export interface LineColumn { + line: number + column: number +} + export interface OverwriteOptions { contentOnly: boolean } diff --git a/napi/parser/src/magic_string.rs b/napi/parser/src/magic_string.rs index dd650d41d013f..db03376918b28 100644 --- a/napi/parser/src/magic_string.rs +++ b/napi/parser/src/magic_string.rs @@ -2,6 +2,7 @@ // use std::sync::Arc; use napi_derive::napi; +use oxc_data_structures::rope::{get_line_column, Rope}; // use oxc_sourcemap::napi::SourceMap; use self_cell::self_cell; @@ -10,6 +11,7 @@ use string_wizard::MagicString as MS; #[napi] pub struct MagicString { cell: MagicStringImpl, + rope: Option, } self_cell!( @@ -22,10 +24,19 @@ self_cell!( impl MagicString { pub fn new(source_text: String) -> Self { - Self { cell: MagicStringImpl::new(source_text, |s| string_wizard::MagicString::new(s)) } + Self { + cell: MagicStringImpl::new(source_text, |s| string_wizard::MagicString::new(s)), + rope: None, + } } } +#[napi(object)] +pub struct LineColumn { + pub line: u32, + pub column: u32, +} + #[napi(object)] pub struct OverwriteOptions { pub content_only: bool, @@ -40,11 +51,21 @@ pub struct SourceMapOptions { #[napi] impl MagicString { + /// Get source text from utf8 offset. #[napi] pub fn get_source_text(&self, start: u32, end: u32) -> &str { &self.cell.borrow_owner()[start as usize..end as usize] } + /// Get 0-based line and column number from utf8 offset. + #[napi] + pub fn get_line_column_number(&mut self, offset: u32) -> LineColumn { + let source_text = self.cell.borrow_owner(); + let rope = self.rope.get_or_insert_with(|| Rope::from_str(source_text)); + let (line, column) = get_line_column(rope, offset, source_text); + LineColumn { line, column } + } + #[napi] pub fn length(&self) -> u32 { self.cell.borrow_dependent().len() as u32 diff --git a/napi/parser/test/magic_string.test.ts b/napi/parser/test/magic_string.test.ts index 3e3325087174d..02b4670e8d99d 100644 --- a/napi/parser/test/magic_string.test.ts +++ b/napi/parser/test/magic_string.test.ts @@ -19,6 +19,12 @@ describe('simple', () => { // Access source text by utf8 offset. expect(ms.getSourceText(start, end)).toEqual('测试'); + // Access line and column number from utf8 offset. + expect(ms.getLineColumnNumber(start)).toStrictEqual({ + line: 0, + column: 19, + }); + // Magic string manipulation. ms.remove(start, end).append(';'); expect(ms.toString()).toEqual('const s: String = "";');