1use bevy_ecs::{schedule::IntoSystemConfigs as _, world::World};
2use lsp_core::prelude::*;
3mod highlight;
4pub use highlight::*;
5
6mod parse;
7use parse::derive_triples;
8pub use parse::{parse_jsonld_system, parse_source};
9
10pub fn setup_parse(world: &mut World) {
11 use lsp_core::prelude::parse::*;
12 world.schedule_scope(ParseLabel, |_, schedule| {
13 schedule.add_systems((
14 parse_source,
15 parse_jsonld_system.after(parse_source),
16 derive_triples
17 .after(parse_jsonld_system)
18 .before(triples)
19 .before(prefixes),
20 ));
21 });
22}
23
24#[cfg(test)]
25mod tests {
26 use completion::CompletionRequest;
27 use futures::executor::block_on;
28 use lsp_core::{components::*, prelude::*, util::lsp_range_to_range, Tasks};
29 use ropey::Rope;
30 use test_utils::{create_file, setup_world, TestClient};
31 use tracing::info;
32
33 use crate::JsonLd;
34
35 #[test]
36 fn parse_works() {
37 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
38
39 let t1 = r#"
40{
41 "@context" : { "foaf": "http://xmlns.com/foaf/0.1/" },
42 "@id": "http://example.com/ns#me",
43 "foaf:friend": "http://example.com/ns#you"
44}"#;
45 let entity = create_file(&mut world, t1, "http://example.com/ns#", "jsonld", Open);
46
47 let tokens = world.entity(entity).get::<Tokens>().expect("tokens exists");
48 let jsonld = world
49 .entity(entity)
50 .get::<Element<JsonLd>>()
51 .expect("jsonld exists");
52
53 assert_eq!(tokens.0.len(), 17);
54
55 let triples = world
56 .entity(entity)
57 .get::<Triples>()
58 .expect("triples exists");
59
60 assert_eq!(triples.0.len(), 1);
61 }
62
63 #[test_log::test]
64 fn current_triple_works() {
65 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
66
67 let t1 = r#"{
68 "@context" : { "foaf": "http://xmlns.com/foaf/0.1/" },
69 "@id": "http://example.com/ns#me",
70 "foaf:friend": "http://example.com/ns#you"
71}"#;
72 let entity = create_file(&mut world, t1, "http://example.com/ns#", "jsonld", Open);
73
74 world.entity_mut(entity).insert((
76 CompletionRequest(vec![]),
77 PositionComponent(lsp_types::Position {
78 line: 3,
79 character: 6,
80 }),
81 ));
82 world.run_schedule(CompletionLabel);
83
84 let _ = world
85 .entity_mut(entity)
86 .take::<TokenComponent>()
87 .expect("token component");
88 let triple = world
89 .entity_mut(entity)
90 .take::<TripleComponent>()
91 .expect("triple component");
92
93 assert_eq!(triple.target, TripleTarget::Predicate);
94
95 world.entity_mut(entity).insert((
96 CompletionRequest(vec![]),
97 PositionComponent(lsp_types::Position {
98 line: 3,
99 character: 22,
100 }),
101 ));
102 world.run_schedule(CompletionLabel);
103
104 let _ = world
105 .entity_mut(entity)
106 .take::<TokenComponent>()
107 .expect("token component");
108 let triple = world
109 .entity_mut(entity)
110 .take::<TripleComponent>()
111 .expect("triple component");
112
113 assert_eq!(triple.target, TripleTarget::Object);
114 }
115
116 #[test_log::test]
117 fn current_triple_works_2() {
118 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
119
120 let t1 = r#"{
121 "@context": {
122 "foaf": "http://xmlns.com/foaf/0.1/"
123 },
124 "@id": "meee",
125 "@type": "foaf:Document",
126 "foa:": "foaf:Document"
127}
128"#;
129 let entity = create_file(&mut world, t1, "http://example.com/ns#", "jsonld", Open);
130
131 world.entity_mut(entity).insert((
133 CompletionRequest(vec![]),
134 PositionComponent(lsp_types::Position {
135 line: 6,
136 character: 6,
137 }),
138 ));
139 world.run_schedule(CompletionLabel);
140
141 let _ = world
142 .entity_mut(entity)
143 .take::<TokenComponent>()
144 .expect("token component");
145 let triple = world
146 .entity_mut(entity)
147 .take::<TripleComponent>()
148 .expect("triple component");
149
150 assert_eq!(triple.target, TripleTarget::Predicate);
151 }
152
153 #[test_log::test]
154 fn current_triple_works_corrupt() {
155 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
156 lang_turtle::setup_world(&mut world);
157
158 let t1 = r#"{
159 "@context" : { "foaf": "http://xmlns.com/foaf/0.1/" },
160 "@id": "http://example.com/ns#me"
161}"#;
162
163 let t2 = r#"{
164 "@context" : { "foaf": "http://xmlns.com/foaf/0.1/" },
165 "@id": "http://example.com/ns#me",
166 "foa"
167}"#;
168 let entity = create_file(&mut world, t1, "http://example.com/ns#", "jsonld", Open);
169
170 let c = world.resource::<TestClient>().clone();
171 block_on(c.await_futures(|| world.run_schedule(Tasks)));
172
173 world
174 .entity_mut(entity)
175 .insert((Source(t2.to_string()), RopeC(Rope::from_str(t2)), Open));
176 world.run_schedule(ParseLabel);
177
178 world.entity_mut(entity).insert((
180 CompletionRequest(vec![]),
181 PositionComponent(lsp_types::Position {
182 line: 3,
183 character: 6,
184 }),
185 ));
186 world.run_schedule(Tasks);
187 world.run_schedule(Tasks);
188 world.run_schedule(CompletionLabel);
189
190 let _ = world
191 .entity_mut(entity)
192 .take::<TokenComponent>()
193 .expect("token component");
194 let triple = world
195 .entity_mut(entity)
196 .take::<TripleComponent>()
197 .expect("triple component");
198
199 assert_eq!(triple.target, TripleTarget::Predicate);
200
201 let comppletions = world
202 .entity_mut(entity)
203 .take::<CompletionRequest>()
204 .expect("completion request")
205 .0;
206
207 let rope_c = world.entity(entity).get::<RopeC>().expect("rope component");
208
209 for comp in &comppletions {
210 let range = lsp_range_to_range(&comp.edits[0].range, &rope_c).expect("valid range");
211 let txt = rope_c.slice(range).to_string();
212 info!("comp {} {} -> {}", comp.label, txt, comp.edits[0].new_text);
213 }
214
215 assert_eq!(comppletions.len(), 63);
216 }
217
218 #[test_log::test]
219 fn current_triple_works_corrupt_bn() {
220 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
221 lang_turtle::setup_world(&mut world);
222
223 let t1 = r#"{
224 "@context" : { "foaf": "http://xmlns.com/foaf/0.1/" }
225}"#;
226
227 let t2 = r#"{
228 "@context" : { "foaf": "http://xmlns.com/foaf/0.1/" },
229 "foa"
230}"#;
231 let entity = create_file(&mut world, t1, "http://example.com/ns#", "jsonld", Open);
232
233 let c = world.resource::<TestClient>().clone();
234 block_on(c.await_futures(|| world.run_schedule(Tasks)));
235
236 world
237 .entity_mut(entity)
238 .insert((Source(t2.to_string()), RopeC(Rope::from_str(t2)), Open));
239 world.run_schedule(ParseLabel);
240
241 world.entity_mut(entity).insert((
243 CompletionRequest(vec![]),
244 PositionComponent(lsp_types::Position {
245 line: 2,
246 character: 6,
247 }),
248 ));
249 world.run_schedule(Tasks);
250 world.run_schedule(Tasks);
251 world.run_schedule(CompletionLabel);
252
253 let _ = world
254 .entity_mut(entity)
255 .take::<TokenComponent>()
256 .expect("token component");
257
258 let triple = world
259 .entity_mut(entity)
260 .take::<TripleComponent>()
261 .expect("triple component");
262
263 assert_eq!(triple.target, TripleTarget::Predicate);
264
265 let comppletions = world
266 .entity_mut(entity)
267 .take::<CompletionRequest>()
268 .expect("completion request")
269 .0;
270
271 let rope_c = world.entity(entity).get::<RopeC>().expect("rope component");
272
273 for comp in &comppletions {
274 let range = lsp_range_to_range(&comp.edits[0].range, &rope_c).expect("valid range");
275 let txt = rope_c.slice(range).to_string();
276 info!("comp {} {} -> {}", comp.label, txt, comp.edits[0].new_text);
277 }
278
279 assert_eq!(comppletions.len(), 63);
280 }
281}