Skip to content

Commit d892280

Browse files
committed
fix: element reference
1 parent f4f56a7 commit d892280

File tree

8 files changed

+132
-55
lines changed

8 files changed

+132
-55
lines changed

index.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export declare class ElementDirectory {
99
export declare class ElementJsonFile {
1010
static findAll(elementDirectory: ElementDirectory): Array<ElementJsonFile>
1111
getUri(): Uri
12-
getResourceDirectory(): ElementDirectory
12+
getElementDirectory(): ElementDirectory
1313
getContent(): string
1414
parse(): any
1515
getReference(): Array<ElementJsonFileReference>
@@ -21,7 +21,9 @@ export declare class ElementJsonFileReference {
2121
getValueStart(): number
2222
getValueEnd(): number
2323
getNameText(): string
24+
getNameFullText(): string
2425
getValueText(): string
26+
getValueFullText(): string
2527
}
2628

2729
export declare class Module {
@@ -130,6 +132,7 @@ export declare class Resource {
130132
export declare class ResourceDirectory {
131133
static findAll(resource: Resource): Array<ResourceDirectory>
132134
getUri(): Uri
135+
getResource(): Resource
133136
getQualifiers(): Array<Qualifier> | 'base' | 'rawfile' | 'resfile'
134137
}
135138

index.js

Lines changed: 25 additions & 25 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"eslint": "^9.37.0",
7777
"husky": "^9.1.7",
7878
"lint-staged": "^16.1.6",
79+
"magic-string": "^0.30.19",
7980
"npm-run-all2": "^8.0.4",
8081
"tinybench": "^5.0.1",
8182
"typescript": "^5.9.2",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/files/element_json_file.rs

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub struct ElementJsonFile {
1616
source_code: String,
1717
uri: Uri,
1818
#[cfg(not(test))]
19-
resource_directory: Reference<ElementDirectory>,
19+
element_directory: Reference<ElementDirectory>,
2020
}
2121

2222
#[napi]
@@ -34,15 +34,15 @@ impl ElementJsonFile {
3434
}
3535

3636
#[cfg(not(test))]
37-
pub fn new(resource_directory: Reference<ElementDirectory>, uri: &Uri, source_code: String) -> Self {
37+
pub fn new(element_directory: Reference<ElementDirectory>, uri: &Uri, source_code: String) -> Self {
3838
let mut parser = Parser::new();
3939
parser.set_language(&tree_sitter_json::LANGUAGE.into()).unwrap();
4040

4141
Self {
4242
parser,
4343
source_code,
4444
uri: uri.clone(),
45-
resource_directory,
45+
element_directory,
4646
}
4747
}
4848

@@ -74,15 +74,19 @@ impl ElementJsonFile {
7474

7575
#[napi]
7676
#[cfg(not(test))]
77-
pub fn get_resource_directory(&self, env: Env) -> Reference<ElementDirectory> {
78-
self.resource_directory.clone(env).unwrap()
77+
pub fn get_element_directory(&self, env: Env) -> Reference<ElementDirectory> {
78+
self.element_directory.clone(env).unwrap()
7979
}
8080

8181
#[napi]
8282
pub fn get_content(&self) -> String {
8383
self.source_code.clone()
8484
}
8585

86+
fn byte_to_char_index(&self, byte_offset: usize) -> usize {
87+
self.source_code[..byte_offset].chars().count()
88+
}
89+
8690
#[napi]
8791
pub fn parse(&mut self) -> serde_json::Value {
8892
serde_json5::from_str(&self.source_code).unwrap()
@@ -139,16 +143,16 @@ impl ElementJsonFile {
139143
Ok(text) => text,
140144
Err(_) => continue,
141145
};
142-
if key_text.contains("\"name\"") {
143-
name_start = Some(filtered_nodes[1].start_byte());
144-
name_end = Some(filtered_nodes[1].end_byte());
146+
if key_text =="\"name\"" {
147+
name_start = Some(self.byte_to_char_index(filtered_nodes[1].start_byte()));
148+
name_end = Some(self.byte_to_char_index(filtered_nodes[1].end_byte()));
145149
name_text = Some(match filtered_nodes[1].utf8_text(self.source_code.as_bytes()) {
146150
Ok(text) => text.to_string(),
147151
Err(_) => continue,
148152
});
149-
} else if key_text.contains("\"value\"") {
150-
value_start = Some(filtered_nodes[1].start_byte());
151-
value_end = Some(filtered_nodes[1].end_byte());
153+
} else if key_text == "\"value\"" {
154+
value_start = Some(self.byte_to_char_index(filtered_nodes[1].start_byte()));
155+
value_end = Some(self.byte_to_char_index(filtered_nodes[1].end_byte()));
152156
value_text = Some(match filtered_nodes[1].utf8_text(self.source_code.as_bytes()) {
153157
Ok(text) => text.to_string(),
154158
Err(_) => continue,
@@ -161,14 +165,16 @@ impl ElementJsonFile {
161165
if let (Some(name_start), Some(name_end), Some(name_text), Some(value_start), Some(value_end), Some(value_text)) =
162166
(name_start, name_end, name_text, value_start, value_end, value_text)
163167
{
164-
reference.push(ElementJsonFileReference::new(
165-
name_start as u32,
166-
name_end as u32,
167-
name_text,
168-
value_start as u32,
169-
value_end as u32,
170-
value_text,
171-
))
168+
reference.push(
169+
ElementJsonFileReference::new(
170+
name_start as u32,
171+
name_end as u32,
172+
name_text,
173+
value_start as u32,
174+
value_end as u32,
175+
value_text,
176+
)
177+
)
172178
}
173179
}
174180
}
@@ -183,17 +189,39 @@ impl ElementJsonFile {
183189
mod tests {
184190
use super::*;
185191

192+
fn slice(s: &str, start: usize, end_exclusive: usize) -> String {
193+
let mut byte_start = 0usize;
194+
let mut byte_end = s.len();
195+
for (i, (bpos, _)) in s.char_indices().enumerate() {
196+
if i == start { byte_start = bpos; }
197+
if i == end_exclusive { byte_end = bpos; break; }
198+
}
199+
s[byte_start..byte_end].to_string()
200+
}
201+
186202
#[test]
187203
fn test_get_reference() {
188204
let mock_str = String::from("{ \"string\": [{ \"name\": \"test1\", \"value\": \"test1-value\" }] }");
189205
let mut element_json_file = ElementJsonFile::new(&Uri::file("test.json".to_string()), mock_str.clone());
190206
let references = element_json_file.get_reference();
191207
assert_eq!(references.len(), 1);
192-
assert_eq!(references[0].get_name_text(), "\"test1\"");
193-
assert_eq!(references[0].get_value_text(), "\"test1-value\"");
194-
assert_eq!(references[0].get_name_start(), 23);
195-
assert_eq!(references[0].get_name_end(), 30);
196-
assert_eq!(references[0].get_value_start(), 41);
197-
assert_eq!(references[0].get_value_end(), 54);
208+
assert_eq!(references[0].get_name_full_text(), "\"test1\"");
209+
assert_eq!(references[0].get_value_full_text(), "\"test1-value\"");
210+
assert_eq!(
211+
slice(
212+
&mock_str,
213+
references[0].get_name_start() as usize,
214+
references[0].get_name_end() as usize
215+
),
216+
references[0].get_name_full_text()
217+
);
218+
assert_eq!(
219+
slice(
220+
&mock_str,
221+
references[0].get_value_start() as usize,
222+
references[0].get_value_end() as usize
223+
),
224+
references[0].get_value_full_text()
225+
);
198226
}
199227
}

src/references/element_json_file_reference.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,27 @@ impl ElementJsonFileReference {
4545

4646
#[napi]
4747
pub fn get_name_text(&self) -> String {
48+
let s = self.name_text.as_str();
49+
let s = if s.starts_with('"') { &s[1..] } else { s };
50+
let s = if s.ends_with('"') { &s[..s.len() - 1] } else { s };
51+
s.to_string()
52+
}
53+
54+
#[napi]
55+
pub fn get_name_full_text(&self) -> String {
4856
self.name_text.clone()
4957
}
5058

5159
#[napi]
5260
pub fn get_value_text(&self) -> String {
61+
let s = self.value_text.as_str();
62+
let s = if s.starts_with('"') { &s[1..] } else { s };
63+
let s = if s.ends_with('"') { &s[..s.len() - 1] } else { s };
64+
s.to_string()
65+
}
66+
67+
#[napi]
68+
pub fn get_value_full_text(&self) -> String {
5369
self.value_text.clone()
5470
}
5571
}

src/resource_directory.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,31 @@ use crate::utils::qualifier::utils_impl::QualifierUtils;
33
use crate::utils::uri::Uri;
44
use core::str;
55
use napi::bindgen_prelude::Reference;
6+
use napi::Env;
67
use napi_derive::napi;
78
use serde_json::Value;
89
use std::path::Path;
910

1011
#[napi]
11-
#[derive(Clone)]
1212
pub struct ResourceDirectory {
1313
uri: Uri,
14+
resource: Reference<Resource>,
1415
}
1516

1617
#[napi]
1718
impl ResourceDirectory {
1819
#[napi]
19-
pub fn find_all(resource: Reference<Resource>) -> Vec<ResourceDirectory> {
20+
pub fn find_all(resource: Reference<Resource>, env: Env) -> Vec<ResourceDirectory> {
2021
let mut resource_directories = Vec::new();
2122
let qualified_directories = resource.get_qualified_directories();
2223

2324
for qualified_directory in qualified_directories {
24-
resource_directories.push(ResourceDirectory { uri: qualified_directory })
25+
resource_directories.push(
26+
ResourceDirectory {
27+
uri: qualified_directory,
28+
resource: resource.clone(env).unwrap()
29+
}
30+
)
2531
}
2632

2733
resource_directories
@@ -32,6 +38,11 @@ impl ResourceDirectory {
3238
self.uri.clone()
3339
}
3440

41+
#[napi]
42+
pub fn get_resource(&self, env: Env) -> Reference<Resource> {
43+
self.resource.clone(env).unwrap()
44+
}
45+
3546
#[napi(ts_return_type = "Array<Qualifier> | 'base' | 'rawfile' | 'resfile'")]
3647
pub fn get_qualifiers(&self) -> Value {
3748
let directory_name = Path::new(&self.uri.fs_path()).file_name().unwrap_or_default().to_string_lossy().to_string();

test/index.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'node:path'
2+
import MagicString from 'magic-string'
23
import { describe, expect } from 'vitest'
34
import { ElementDirectory, ElementJsonFile, Module, Product, Project, ProjectDetector, Resource, ResourceDirectory, Uri } from '../index.js'
45

@@ -74,11 +75,25 @@ describe.sequential('projectDetector', (it) => {
7475
expect(harmonyProject1MainBaseResource).toBeDefined()
7576
})
7677

78+
let stringJsonFile: ElementJsonFile
79+
7780
it.sequential('elementDirectory & elementJsonFile.findAll', () => {
7881
const elementDirectory = ElementDirectory.from(harmonyProject1MainBaseResource)
7982
const elementJsonFiles = ElementJsonFile.findAll(elementDirectory)
8083
expect(elementJsonFiles.length).toBeGreaterThanOrEqual(1)
81-
const stringJsonFile = elementJsonFiles.find(elementJsonFile => elementJsonFile.getUri().toString().includes('string.json'))!
84+
stringJsonFile = elementJsonFiles.find(elementJsonFile => elementJsonFile.getUri().toString().includes('string.json'))!
8285
expect(stringJsonFile).toBeDefined()
8386
})
87+
88+
it.sequential('elementJsonFile.getReference', () => {
89+
const references = stringJsonFile.getReference()
90+
expect(references.length).toBeGreaterThanOrEqual(1)
91+
const ms = new MagicString(stringJsonFile.getContent())
92+
for (const reference of references) {
93+
expect(ms.slice(reference.getNameStart(), reference.getNameEnd())).toBe(reference.getNameFullText())
94+
expect(ms.slice(reference.getValueStart(), reference.getValueEnd())).toBe(reference.getValueFullText())
95+
expect(reference.getNameFullText()).toBe(`"${reference.getNameText()}"`)
96+
expect(reference.getValueFullText()).toBe(`"${reference.getValueText()}"`)
97+
}
98+
})
8499
})

0 commit comments

Comments
 (0)