// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub fn collect_wgsl_import_targets(
spec : String,
prefix : String,
targets : Array[WgslImportTarget],
) -> Unit {
parse_wgsl_import_targets(trim_trailing_semicolons(spec), prefix, targets) catch {
_ => ()
}
}
///|
pub fn normalize_shader_rel_path(rel : String) -> String {
let mut text = rel.trim().to_owned()
let n = text.length()
let mut i = 0
while i < n && text.code_unit_at(i).to_int() == 47 { // '/'
i = i + 1
}
if i != 0 {
text = text[i:n].to_owned()
}
while text.has_prefix("./") {
text = text[2:text.length()].to_owned()
}
if text.has_prefix("assets/") {
text = text[7:text.length()].to_owned()
}
let normalized_segments : Array[String] = []
for raw_segment in text.split("/") {
let segment = raw_segment.to_owned().trim().to_owned()
if segment == "" || segment == "." {
continue
}
if segment == ".." {
if normalized_segments.length() > 0 {
normalized_segments.pop() |> ignore
}
continue
}
normalized_segments.push(segment)
}
normalized_segments.join("/")
}
///|
fn shader_parent_rel_path(rel_path : String) -> String {
let normalized = normalize_shader_rel_path(rel_path)
if normalized == "" {
return ""
}
let segments : Array[String] = []
for raw_segment in normalized.split("/") {
let segment = raw_segment.to_owned()
if segment != "" {
segments.push(segment)
}
}
if segments.length() == 0 {
return ""
}
segments.pop() |> ignore
segments.join("/")
}
///|
fn unquote_wgsl_import_path(import_path : String) -> String? {
let trimmed = import_path.trim().to_owned()
if trimmed.length() >= 2 &&
trimmed.code_unit_at(0).to_int() == 34 &&
trimmed.code_unit_at(trimmed.length() - 1).to_int() == 34 {
return Some(trimmed[1:trimmed.length() - 1].to_owned())
}
None
}
///|
fn wgsl_import_looks_like_file_path(import_path : String) -> Bool {
if unquote_wgsl_import_path(import_path) is Some(_) {
return true
}
let trimmed = import_path.trim().to_owned()
if trimmed == "" {
return false
}
trimmed.contains("/") ||
trimmed.has_suffix(".wgsl") ||
trimmed.has_prefix("./") ||
trimmed.has_prefix("../")
}
///|
pub fn resolve_wgsl_import_file_path_from_registry(
registry : WgslSourceRegistry,
importer_rel_path : String,
import_path : String,
) -> String? {
guard wgsl_import_looks_like_file_path(import_path) else { return None }
let raw_path = match unquote_wgsl_import_path(import_path) {
Some(path) => path
None => import_path.trim().to_owned()
}
let normalized = if raw_path.has_prefix("./") || raw_path.has_prefix("../") {
let parent = shader_parent_rel_path(importer_rel_path)
if parent == "" {
normalize_shader_rel_path(raw_path)
} else {
normalize_shader_rel_path("\{parent}/\{raw_path}")
}
} else {
normalize_shader_rel_path(raw_path)
}
if normalized == "" {
return None
}
if registry.registered_source(normalized) is Some(_) {
return Some(normalized)
}
None
}
///|