Skip to content

Commit d5ee5f6

Browse files
committed
native: support json module
1 parent 2825c2f commit d5ee5f6

File tree

3 files changed

+78
-24
lines changed

3 files changed

+78
-24
lines changed

Cargo.lock

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

native/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ edition = "2021"
55

66
[dependencies]
77
lexer = { path = "../lexer" }
8-
oxc_resolver = "2.1.1"
98
indexmap = "2.7.0"
9+
oxc_resolver = "2.1.1"
10+
serde_json = "1.0.133"

native/src/main.rs

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use indexmap::IndexSet;
22
use lexer::CommonJSModuleLexer;
33
use oxc_resolver::{ResolveError, ResolveOptions, Resolver};
4-
use std::io::{stdout, Write};
4+
use std::io::{self, stdout, Write};
55
use std::path::Path;
66
use std::{env, fs};
77

@@ -20,6 +20,17 @@ fn main() {
2020
while requires.len() > 0 {
2121
let (js_filename, call_mode) = requires.pop().unwrap();
2222
let code = fs::read_to_string(&js_filename).expect(("failed to read ".to_owned() + js_filename.as_str()).as_str());
23+
if js_filename.ends_with(".json") {
24+
let value: serde_json::Value = serde_json::from_str(&code).unwrap();
25+
if let Some(value) = value.as_object() {
26+
for key in value.keys() {
27+
if is_js_identifier(&key) {
28+
named_exports.insert(key.clone());
29+
}
30+
}
31+
}
32+
continue;
33+
}
2334
let lexer = CommonJSModuleLexer::init(&js_filename, &code).expect("failed to parse module");
2435
let (exports, reexports) = lexer.analyze(&node_env, call_mode);
2536
if exports.len() == 0 && reexports.len() == 1 && named_exports.len() == 0 {
@@ -54,9 +65,11 @@ fn main() {
5465
}
5566
}
5667
for name in named_exports {
57-
stdout
58-
.write_all((name + "\n").as_bytes())
59-
.expect("failed to write result to stdout");
68+
if is_js_identifier(&name) {
69+
stdout
70+
.write_all((name + "\n").as_bytes())
71+
.expect("failed to write result to stdout");
72+
}
6073
}
6174
}
6275

@@ -91,37 +104,30 @@ fn resolve(wd: &str, specifier: &str, containing_filename: Option<String>) -> Re
91104
.unwrap()
92105
.to_owned()
93106
};
94-
if fs::exists(&fullpath).expect("Can't check existence of file") {
107+
108+
if (fullpath.ends_with(".js") || fullpath.ends_with(".cjs") || fullpath.ends_with(".json"))
109+
&& file_exists(&fullpath).expect("Can't check existence of file")
110+
{
95111
return Ok(fullpath);
96112
}
97-
let maybe_exists = fullpath.to_owned() + ".cjs";
98-
if fs::exists(&maybe_exists).expect("Can't check existence of file") {
99-
return Ok(maybe_exists);
100-
}
101-
let maybe_exists = fullpath.to_owned() + ".js";
102-
if fs::exists(&maybe_exists).expect("Can't check existence of file") {
103-
return Ok(maybe_exists);
104-
}
105-
let maybe_exists = fullpath.to_owned() + "/index.cjs";
106-
if fs::exists(&maybe_exists).expect("Can't check existence of file") {
107-
return Ok(maybe_exists);
108-
}
109-
let maybe_exists = fullpath.to_owned() + "/index.js";
110-
if fs::exists(&maybe_exists).expect("Can't check existence of file") {
111-
return Ok(maybe_exists);
112-
}
113113
if fullpath.ends_with(".js") {
114114
let maybe_exists = fullpath[..fullpath.len() - 3].to_owned() + ".cjs";
115-
if fs::exists(&maybe_exists).expect("Can't check existence of file") {
115+
if file_exists(&maybe_exists).expect("Can't check existence of file") {
116116
return Ok(maybe_exists);
117117
}
118118
}
119119
if fullpath.ends_with(".cjs") {
120120
let maybe_exists = fullpath[..fullpath.len() - 4].to_owned() + ".js";
121-
if fs::exists(&maybe_exists).expect("Can't check existence of file") {
121+
if file_exists(&maybe_exists).expect("Can't check existence of file") {
122122
return Ok(maybe_exists);
123123
}
124124
}
125+
let maybe_exists = fullpath.to_owned() + ".cjs";
126+
if file_exists(&maybe_exists).expect("Can't check existence of file")
127+
&& !dir_exists(&fullpath).expect("Can't check existence of directory")
128+
{
129+
return Ok(maybe_exists);
130+
}
125131

126132
// `/path/to/wd/node_modules/react/index` -> `react/index`
127133
if specifier.starts_with("/") {
@@ -139,6 +145,52 @@ fn resolve(wd: &str, specifier: &str, containing_filename: Option<String>) -> Re
139145
Ok(ret.path().to_str().unwrap().to_owned())
140146
}
141147

148+
pub fn dir_exists(path: &str) -> io::Result<bool> {
149+
match fs::metadata(path) {
150+
Ok(meta) => Ok(meta.is_dir() || meta.is_symlink()),
151+
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
152+
Err(error) => Err(error),
153+
}
154+
}
155+
156+
pub fn file_exists(path: &str) -> io::Result<bool> {
157+
match fs::metadata(path) {
158+
Ok(meta) => Ok(meta.is_file()),
159+
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
160+
Err(error) => Err(error),
161+
}
162+
}
163+
164+
fn is_js_identifier(s: &str) -> bool {
165+
if s.len() == 0 {
166+
return false;
167+
}
168+
let first_char = s.chars().next().unwrap();
169+
if !is_alphabetic(first_char) {
170+
return false;
171+
}
172+
for c in s.chars() {
173+
if !is_alphabetic(c) && !is_numberic(c) {
174+
return false;
175+
}
176+
}
177+
return true;
178+
}
179+
180+
fn is_alphabetic(c: char) -> bool {
181+
match c {
182+
'a'..='z' | 'A'..='Z' | '_' | '$' => true,
183+
_ => false,
184+
}
185+
}
186+
187+
fn is_numberic(c: char) -> bool {
188+
match c {
189+
'0'..='9' => true,
190+
_ => false,
191+
}
192+
}
193+
142194
fn is_node_builtin_module(specifier: &str) -> bool {
143195
match specifier {
144196
"_http_agent"

0 commit comments

Comments
 (0)