1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4use std::collections::HashMap;
5use std::path::PathBuf;
6
7use super::JsComponentDefinition;
8use super::JsDiagnostic;
9use itertools::Itertools;
10use slint_interpreter::ComponentCompiler;
11
12/// ComponentCompiler is the entry point to the Slint interpreter that can be used
13/// to load .slint files or compile them on-the-fly from a string.
14#[napi(js_name = "ComponentCompiler")]
15pub struct JsComponentCompiler {
16 internal: ComponentCompiler,
17}
18
19#[napi]
20impl JsComponentCompiler {
21 /// Returns a new ComponentCompiler.
22 #[napi(constructor)]
23 pub fn new() -> Self {
24 let mut compiler = ComponentCompiler::default();
25 let include_paths = match std::env::var_os("SLINT_INCLUDE_PATH") {
26 Some(paths) => {
27 std::env::split_paths(&paths).filter(|path| !path.as_os_str().is_empty()).collect()
28 }
29 None => vec![],
30 };
31 let library_paths = match std::env::var_os("SLINT_LIBRARY_PATH") {
32 Some(paths) => std::env::split_paths(&paths)
33 .filter_map(|entry| {
34 entry
35 .to_str()
36 .unwrap_or_default()
37 .split('=')
38 .collect_tuple()
39 .map(|(k, v)| (k.into(), v.into()))
40 })
41 .collect(),
42 None => std::collections::HashMap::new(),
43 };
44
45 compiler.set_include_paths(include_paths);
46 compiler.set_library_paths(library_paths);
47 Self { internal: compiler }
48 }
49
50 #[napi(setter)]
51 pub fn set_include_paths(&mut self, include_paths: Vec<String>) {
52 self.internal.set_include_paths(include_paths.iter().map(|p| PathBuf::from(p)).collect());
53 }
54
55 #[napi(getter)]
56 pub fn include_paths(&self) -> Vec<String> {
57 self.internal
58 .include_paths()
59 .iter()
60 .map(|p| p.to_str().unwrap_or_default().to_string())
61 .collect()
62 }
63
64 #[napi(setter)]
65 pub fn set_library_paths(&mut self, paths: HashMap<String, String>) {
66 let mut library_paths = HashMap::new();
67 for (key, path) in paths {
68 library_paths.insert(key, PathBuf::from(path));
69 }
70
71 self.internal.set_library_paths(library_paths);
72 }
73
74 #[napi(getter)]
75 pub fn library_paths(&self) -> HashMap<String, String> {
76 let mut library_paths = HashMap::new();
77
78 for (key, path) in self.internal.library_paths() {
79 library_paths.insert(key.clone(), path.to_str().unwrap_or_default().to_string());
80 }
81
82 library_paths
83 }
84
85 #[napi(setter)]
86 pub fn set_style(&mut self, style: String) {
87 self.internal.set_style(style);
88 }
89
90 #[napi(getter)]
91 pub fn style(&self) -> Option<String> {
92 self.internal.style().cloned()
93 }
94
95 // todo: set_file_loader
96
97 #[napi(getter)]
98 pub fn diagnostics(&self) -> Vec<JsDiagnostic> {
99 self.internal.diagnostics().iter().map(|d| JsDiagnostic::from(d.clone())).collect()
100 }
101
102 /// Compile a .slint file into a ComponentDefinition
103 ///
104 /// Returns the compiled `ComponentDefinition` if there were no errors.
105 #[napi]
106 pub fn build_from_path(&mut self, path: String) -> Option<JsComponentDefinition> {
107 spin_on::spin_on(self.internal.build_from_path(PathBuf::from(path))).map(|d| d.into())
108 }
109
110 /// Compile some .slint code into a ComponentDefinition
111 #[napi]
112 pub fn build_from_source(
113 &mut self,
114 source_code: String,
115 path: String,
116 ) -> Option<JsComponentDefinition> {
117 spin_on::spin_on(self.internal.build_from_source(source_code, PathBuf::from(path)))
118 .map(|d| d.into())
119 }
120}
121