diff --git a/examples/deno-jsonc/deno.jsonc b/examples/deno-jsonc/deno.jsonc new file mode 100644 index 000000000..9064591b1 --- /dev/null +++ b/examples/deno-jsonc/deno.jsonc @@ -0,0 +1,15 @@ +// THIS FILE HAS ALL KINDS OF COMMENTS POSSIBLE TO TEST JSONC +{ + //some random comment + "tasks": { + // random afterline comment + /* :) */ "dev": "deno run --watch main.ts", + "start": "deno start main.ts" + } /* + This + is some multiline comment + */, + "imports": { + "@std/assert": "jsr:@std/assert@1" + } +} diff --git a/examples/deno-jsonc/deno.lock b/examples/deno-jsonc/deno.lock new file mode 100644 index 000000000..3513c0ffe --- /dev/null +++ b/examples/deno-jsonc/deno.lock @@ -0,0 +1,18 @@ +{ + "version": "4", + "specifiers": { + "jsr:@std/assert@1": "1.0.8", + "jsr:@std/internal@^1.0.5": "1.0.5" + }, + "jsr": { + "@std/assert@1.0.8": { + "integrity": "ebe0bd7eb488ee39686f77003992f389a06c3da1bbd8022184804852b2fa641b", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/internal@1.0.5": { + "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba" + } + } +} diff --git a/examples/deno-jsonc/main.ts b/examples/deno-jsonc/main.ts new file mode 100644 index 000000000..bdf52b985 --- /dev/null +++ b/examples/deno-jsonc/main.ts @@ -0,0 +1,7 @@ +export function add(a: number, b: number): number { + return a + b; +} +// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts +if (import.meta.main) { + console.log("Add 2 + 3 =", add(2, 3)); +} \ No newline at end of file diff --git a/examples/deno-jsonc/main_test.ts b/examples/deno-jsonc/main_test.ts new file mode 100644 index 000000000..3d981e9be --- /dev/null +++ b/examples/deno-jsonc/main_test.ts @@ -0,0 +1,6 @@ +import { assertEquals } from "@std/assert"; +import { add } from "./main.ts"; + +Deno.test(function addTest() { + assertEquals(add(2, 3), 5); +}); diff --git a/src/nixpacks/app.rs b/src/nixpacks/app.rs index d94e8416e..7aea9a17f 100644 --- a/src/nixpacks/app.rs +++ b/src/nixpacks/app.rs @@ -190,6 +190,47 @@ impl App { Ok(toml_file) } + /// Parse jsonc files as json by ignoring all kinds of comments + pub fn read_jsonc(&self, name: &str) -> Result + where + T: DeserializeOwned, + { + let mut cleaned_jsonc = String::new(); + let contents = self.read_file(name)?; + let mut chars = contents.chars().peekable(); + while let Some(current_char) = chars.next() { + match current_char { + '/' if chars.peek() == Some(&'/') => { + while let Some(&next_char) = chars.peek() { + chars.next(); + if next_char == '\n' { + break; + } + } + } + '/' if chars.peek() == Some(&'*') => { + chars.next(); + loop { + match chars.next() { + Some('*') if chars.peek() == Some(&'/') => { + chars.next(); + break; + } + None => break, + _ => continue, + } + } + } + _ => cleaned_jsonc.push(current_char), + } + } + let value: T = serde_json::from_str(cleaned_jsonc.as_str()).with_context(|| { + let relative_path = self.strip_source_path(Path::new(name)).unwrap(); + format!("Error reading {} as JSONC", relative_path.to_str().unwrap()) + })?; + Ok(value) + } + /// Try to yaml-parse a file. pub fn read_yaml(&self, name: &str) -> Result where @@ -281,6 +322,14 @@ mod tests { Ok(()) } + #[test] + fn test_read_jsonc_file() -> Result<()> { + let app = App::new("./examples/deno-jsonc")?; + let value: Map = app.read_jsonc("deno.jsonc")?; + assert!(value.get("tasks").is_some()); + Ok(()) + } + #[test] fn test_read_toml_file() -> Result<()> { let app = App::new("./examples/rust-rocket")?; diff --git a/src/providers/deno.rs b/src/providers/deno.rs index a5289ec46..3deef7bee 100644 --- a/src/providers/deno.rs +++ b/src/providers/deno.rs @@ -82,7 +82,7 @@ impl DenoProvider { if app.includes_file("deno.json") || app.includes_file("deno.jsonc") { let deno_json: DenoJson = app .read_json("deno.json") - .or_else(|_| app.read_json("deno.jsonc"))?; + .or_else(|_| app.read_jsonc("deno.jsonc"))?; if let Some(tasks) = deno_json.tasks { if let Some(start) = tasks.start {