1pub(crate) mod project;
2pub mod token;
3
4pub use token::{EditHint, EnumOption, NlToken, NlTokenKind, OpChoice, OpSym, TypeTag, WordSym};
5
6use serde::Serialize;
7use std::rc::Rc;
8
9use crate::intellisense::diagnostic::Diagnostic;
10use crate::intellisense::NlLabelResolver;
11use crate::variable::VariableType;
12
13pub fn encode_string(value: &str) -> Option<String> {
14 if !value.contains('"') {
15 Some(format!("\"{value}\""))
16 } else if !value.contains('\'') {
17 Some(format!("'{value}'"))
18 } else {
19 None
20 }
21}
22
23pub(crate) fn enum_options(
24 name: Option<&str>,
25 values: &[Rc<str>],
26 labels: Option<&NlLabelResolver>,
27) -> Vec<EnumOption> {
28 values
29 .iter()
30 .map(|v| EnumOption {
31 label: labels
32 .zip(name)
33 .and_then(|(resolve, n)| resolve(n, v))
34 .filter(|l| !l.is_empty())
35 .unwrap_or_else(|| v.to_string()),
36 source: encode_string(v),
37 })
38 .collect()
39}
40
41pub(crate) fn subject_enum_options(
42 subject: &VariableType,
43 labels: Option<&NlLabelResolver>,
44) -> Option<Vec<EnumOption>> {
45 match subject {
46 VariableType::Enum(name, values) => Some(enum_options(name.as_deref(), values, labels)),
47 VariableType::Nullable(inner) | VariableType::Array(inner) => {
48 subject_enum_options(inner, labels)
49 }
50 _ => None,
51 }
52}
53
54#[derive(Debug, Clone)]
55pub struct NlRequest {
56 pub id: String,
57 pub expression: String,
58 pub unary: bool,
59 pub subject_type: Option<VariableType>,
60}
61
62#[derive(Debug, Clone, Serialize)]
63#[serde(rename_all = "camelCase")]
64pub struct NlResult {
65 pub id: String,
66 pub tokens: Vec<NlToken>,
67 pub enums: Vec<Vec<EnumOption>>,
68 pub diagnostics: Vec<Diagnostic>,
69 #[serde(skip)]
70 pub subject_type: Option<VariableType>,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub subject_options: Option<Vec<EnumOption>>,
73}