Skip to content

Commit 3751fde

Browse files
author
skidy89
committed
reordenate the lib
1 parent e5d02d5 commit 3751fde

File tree

8 files changed

+179
-177
lines changed

8 files changed

+179
-177
lines changed

__test__/languages.d.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,15 @@
33

44
/* eslint-disable */
55
export interface Lang {
6-
/** This is a {placeholder} test. */
7-
'test_placeholder': (args: { placeholder: string }) => string;
8-
/**
9-
* [
10-
* "value1",
11-
* "value2 with {placeholder}",
12-
* "value3",
13-
* ]
14-
*/
15-
'tested_array': string[];
16-
/** hello world */
17-
'hello': string;
186
/**
19-
* "this is
7+
* this is
208
* a multi-line
219
* string
22-
* test"
10+
* test
2311
*/
2412
'test': string;
13+
/** hello world */
14+
'hello': string;
2515
/**
2616
* [
2717
* "key1",
@@ -30,6 +20,16 @@ export interface Lang {
3020
* ]
3121
*/
3222
'array': string[];
23+
/** This is a {placeholder} test. */
24+
'test_placeholder': (args: { placeholder: string }) => string;
25+
/**
26+
* [
27+
* "value1",
28+
* "value2 with {placeholder}",
29+
* "value3",
30+
* ]
31+
*/
32+
'tested_array': string[];
3333
}
3434

3535
export interface Langs {

__test__/sec/e.lang

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# test file
2+
# This file is used to test the project
3+
# It contains test cases for various functionalities
4+
# including language loading and processing.
5+
# The tests are written using the AVA testing framework.
6+
7+
hello = "hello world"
8+
test = "this is
9+
a multi-line
10+
string
11+
test"
12+
array = [
13+
"key1",
14+
"key2",
15+
"key3"
16+
]
17+
# it should not generate placeholder for array types
18+
test_placeholder = "This is a {placeholder} test."
19+
tested_array = [
20+
"value1",
21+
"value2 with {placeholder}",
22+
"value3",
23+
]

index.d.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
/* auto-generated by NAPI-RS */
22
/* eslint-disable */
3-
export declare function clearLangCache(): void
4-
53
export declare function generateTypescriptDefs(dir: string, output: string, genPlaceholder?: boolean | undefined | null): void
64

7-
export declare function loadChdlang(dir: string): object
8-
9-
export declare function loadLang(path: string): object
5+
export declare function loadCachedLangs(dir: string): object
106

117
export declare function loadLangs(dir: string): object

index.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,6 @@ if (!nativeBinding) {
572572
}
573573

574574
module.exports = nativeBinding
575-
module.exports.clearLangCache = nativeBinding.clearLangCache
576575
module.exports.generateTypescriptDefs = nativeBinding.generateTypescriptDefs
577-
module.exports.loadChdlang = nativeBinding.loadChdlang
578-
module.exports.loadLang = nativeBinding.loadLang
576+
module.exports.loadCachedLangs = nativeBinding.loadCachedLangs
579577
module.exports.loadLangs = nativeBinding.loadLangs

src/cache.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::loader::LangCache;
2+
use once_cell::sync::OnceCell;
3+
4+
static LANG_CACHE: OnceCell<LangCache> = OnceCell::new();
5+
6+
pub fn get() -> Option<&'static LangCache> {
7+
LANG_CACHE.get()
8+
}
9+
10+
pub fn set(langs: LangCache) {
11+
let _ = LANG_CACHE.set(langs);
12+
}

src/lib.rs

Lines changed: 16 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,164 +1,31 @@
1+
pub mod cache;
2+
pub mod loader;
3+
pub mod parser;
14
use napi::{
25
bindgen_prelude::{JsObjectValue, Object},
36
Env, Error, Result,
47
};
58
use napi_derive::napi;
6-
use once_cell::sync::Lazy;
7-
use rayon::prelude::*;
9+
use std::fs;
10+
use std::path::Path;
811

9-
use std::{collections::HashMap, fs, path::Path, sync::RwLock};
10-
11-
type LangCache = HashMap<String, HashMap<String, String>>;
12-
static LANG_CACHE: Lazy<RwLock<Option<LangCache>>> = Lazy::new(|| RwLock::new(None));
13-
14-
#[napi]
15-
pub fn load_lang(env: &Env, path: String) -> Result<Object<'_>> {
16-
let path = Path::new(&path);
17-
if !path.is_file() {
18-
return Err(Error::from_reason(format!(
19-
"Path '{}' is not a file",
20-
path.display()
21-
)));
22-
}
23-
24-
let data = fs::read_to_string(path)
25-
.map_err(|e| Error::from_reason(format!("Cannot read file '{}': {}", path.display(), e)))?;
26-
let map = parse_lang_data(&data);
27-
let mut js = Object::new(&env)?;
28-
for (k, v) in map {
29-
js.set_named_property(&k, env.create_string(&v)?)?;
30-
}
31-
Ok(js)
32-
}
33-
34-
fn parse_lang_data(data: &str) -> HashMap<String, String> {
35-
let mut map = HashMap::new();
36-
let mut ckey: Option<String> = None;
37-
let mut cval = String::new();
38-
let mut mtl = false;
39-
let mut is_array = false;
40-
41-
for line in data.lines() {
42-
let line = line.trim_end();
43-
if line.is_empty() || line.starts_with('#') {
44-
continue;
45-
}
46-
47-
if mtl {
48-
cval.push_str(line);
49-
cval.push('\n');
50-
if (is_array && line.trim().ends_with(']'))
51-
|| (!is_array && line.trim().ends_with('"') && !line.trim().ends_with("\\\""))
52-
{
53-
mtl = false;
54-
if let Some(key) = ckey.take() {
55-
map.insert(key, cval.trim().to_string());
56-
}
57-
cval.clear();
58-
is_array = false;
59-
}
60-
continue;
61-
}
62-
63-
if let Some(pos) = line.find('=') {
64-
let key = line[..pos].trim().to_string();
65-
let value = line[pos + 1..].trim();
66-
67-
if key.is_empty() {
68-
continue;
69-
}
70-
71-
if value.starts_with('[') {
72-
if !value.ends_with(']') {
73-
mtl = true;
74-
is_array = true;
75-
ckey = Some(key);
76-
cval = value.to_string();
77-
cval.push('\n');
78-
} else {
79-
map.insert(key, value.to_string());
80-
}
81-
} else if value.starts_with('"') {
82-
if !value.ends_with('"') || value.ends_with("\\\"") {
83-
mtl = true;
84-
ckey = Some(key);
85-
cval = value.to_string();
86-
cval.push('\n');
87-
} else {
88-
map.insert(key, value.trim_matches('"').to_string());
89-
}
90-
} else {
91-
map.insert(key, value.to_string());
92-
}
93-
}
94-
}
95-
96-
map
97-
}
98-
99-
pub fn validate_path_is_dir(dir: &str) -> Result<&Path> {
100-
let dirpath = Path::new(dir);
101-
if !dirpath.is_dir() {
102-
return Err(Error::from_reason(format!(
103-
"Path '{}' is not a directory",
104-
dir
105-
)));
106-
}
107-
Ok(dirpath)
108-
}
109-
110-
pub fn validate_files(files: &Path) -> Result<Vec<std::path::PathBuf>> {
111-
let fl: Vec<_> = fs::read_dir(files)
112-
.map_err(|e| Error::from_reason(e.to_string()))?
113-
.filter_map(|entry| {
114-
let entry = entry.ok()?;
115-
let path = entry.path();
116-
if path.extension()? == "lang" {
117-
Some(path)
118-
} else {
119-
None
120-
}
121-
})
122-
.collect();
123-
Ok(fl)
124-
}
125-
126-
fn load_lang_dsk(dir: &str) -> Result<LangCache> {
127-
let dirpath = validate_path_is_dir(dir)?;
128-
let files = validate_files(dirpath)?;
129-
let results: LangCache = files
130-
.par_iter()
131-
.filter_map(|path| {
132-
let name = path.file_stem()?.to_string_lossy().to_string();
133-
let data = fs::read_to_string(path).ok()?;
134-
Some((name, parse_lang_data(&data)))
135-
})
136-
.collect();
137-
Ok(results)
138-
}
12+
use crate::loader::{load_lang_dir, LangCache};
13913

14014
#[napi]
141-
pub fn load_langs(env: &Env, dir: String) -> Result<Object<'_>> {
142-
let results = load_lang_dsk(&dir)?;
143-
to_js(env, &results)
15+
pub fn load_langs<'a>(env: &'a Env, dir: String) -> Result<Object<'a>> {
16+
let langs = load_lang_dir(Path::new(&dir))?;
17+
to_js(env, &langs)
14418
}
14519

14620
#[napi]
147-
pub fn load_chdlang(env: &Env, dir: String) -> Result<Object<'_>> {
148-
{
149-
let cache = LANG_CACHE.read().unwrap();
150-
if let Some(cached) = &*cache {
151-
return to_js(env, cached);
152-
}
21+
pub fn load_cached_langs<'a>(env: &'a Env, dir: String) -> Result<Object<'a>> {
22+
if let Some(cached) = cache::get() {
23+
return to_js(env, cached);
15324
}
15425

155-
let langs = load_lang_dsk(&dir)?;
156-
{
157-
let mut cache = LANG_CACHE.write().unwrap();
158-
*cache = Some(langs.clone());
159-
}
160-
161-
to_js(env, &langs)
26+
let langs = load_lang_dir(Path::new(&dir))?;
27+
cache::set(langs);
28+
to_js(env, cache::get().unwrap())
16229
}
16330

16431
fn to_js<'a>(env: &'a Env, langs: &LangCache) -> Result<Object<'a>> {
@@ -208,7 +75,7 @@ pub fn generate_typescript_defs(
20875
output: String,
20976
gen_placeholder: Option<bool>,
21077
) -> Result<()> {
211-
let langs = load_lang_dsk(&dir)?;
78+
let langs = load_lang_dir(Path::new(&dir))?;
21279
let mut defs = String::new();
21380
defs.push_str("// THIS FILE WAS GENERATED BY SSL\n");
21481
defs.push_str("// DO NOT EDIT MANUALLY OR ELSE IT WILL BE OVERWRITTEN\n\n");
@@ -271,9 +138,3 @@ pub fn generate_typescript_defs(
271138
}
272139
Ok(())
273140
}
274-
275-
#[napi]
276-
pub fn clear_lang_cache() {
277-
let mut cache = LANG_CACHE.write().unwrap();
278-
*cache = None;
279-
}

src/loader.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use crate::parser::{parse_lang_data, LangMap};
2+
use rayon::prelude::*;
3+
use std::{collections::HashMap, fs, path::Path};
4+
5+
pub type LangCache = HashMap<String, LangMap>;
6+
7+
pub fn load_lang_dir(dir: &Path) -> napi::Result<LangCache> {
8+
if !dir.is_dir() {
9+
return Err(napi::Error::from_reason("Not a directory"));
10+
}
11+
12+
let files: Vec<_> = fs::read_dir(dir)?
13+
.filter_map(|e| {
14+
let p = e.ok()?.path();
15+
(p.extension()? == "lang").then_some(p)
16+
})
17+
.collect();
18+
19+
Ok(
20+
files
21+
.par_iter()
22+
.filter_map(|p| {
23+
let name = p.file_stem()?.to_string_lossy().to_string();
24+
let data = fs::read_to_string(p).ok()?;
25+
Some((name, parse_lang_data(&data)))
26+
})
27+
.collect(),
28+
)
29+
}

0 commit comments

Comments
 (0)