use vize_carton::FxHashMap;
use crate::types::TypeInfo;
#[derive(Debug, Clone, Default)]
pub struct TypeContext {
pub bindings: FxHashMap<String, Binding>,
pub components: FxHashMap<String, ComponentInfo>,
pub props: Vec<Prop>,
pub emits: Vec<Emit>,
pub slots: Vec<Slot>,
pub globals: FxHashMap<String, TypeInfo>,
}
impl TypeContext {
pub fn new() -> Self {
Self::default()
}
pub fn add_binding(&mut self, name: impl Into<String>, binding: Binding) {
self.bindings.insert(name.into(), binding);
}
pub fn get_binding(&self, name: &str) -> Option<&Binding> {
self.bindings.get(name)
}
pub fn add_component(&mut self, name: impl Into<String>, info: ComponentInfo) {
self.components.insert(name.into(), info);
}
pub fn get_component(&self, name: &str) -> Option<&ComponentInfo> {
self.components.get(name)
}
pub fn add_prop(&mut self, prop: Prop) {
self.props.push(prop);
}
pub fn add_emit(&mut self, emit: Emit) {
self.emits.push(emit);
}
pub fn add_slot(&mut self, slot: Slot) {
self.slots.push(slot);
}
pub fn has_binding(&self, name: &str) -> bool {
self.bindings.contains_key(name)
}
pub fn has_component(&self, name: &str) -> bool {
self.components.contains_key(name)
}
}
#[derive(Debug, Clone)]
pub struct Binding {
pub name: String,
pub type_info: TypeInfo,
pub kind: BindingKind,
pub source_offset: Option<u32>,
}
impl Binding {
pub fn new(name: impl Into<String>, type_info: TypeInfo, kind: BindingKind) -> Self {
Self {
name: name.into(),
type_info,
kind,
source_offset: None,
}
}
pub fn with_offset(mut self, offset: u32) -> Self {
self.source_offset = Some(offset);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BindingKind {
Const,
Let,
Var,
Function,
Class,
Import,
Destructure,
Ref,
Computed,
Reactive,
Prop,
SetupReturn,
}
#[derive(Debug, Clone)]
pub struct ComponentInfo {
pub name: String,
pub import_path: Option<String>,
pub props: Vec<Prop>,
pub emits: Vec<Emit>,
pub slots: Vec<Slot>,
pub is_builtin: bool,
}
impl ComponentInfo {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
import_path: None,
props: Vec::new(),
emits: Vec::new(),
slots: Vec::new(),
is_builtin: false,
}
}
pub fn with_import_path(mut self, path: impl Into<String>) -> Self {
self.import_path = Some(path.into());
self
}
pub fn builtin(mut self) -> Self {
self.is_builtin = true;
self
}
}
#[derive(Debug, Clone)]
pub struct Import {
pub local: String,
pub imported: String,
pub module: String,
pub type_info: TypeInfo,
pub is_type_only: bool,
}
impl Import {
pub fn new(local: impl Into<String>, module: impl Into<String>) -> Self {
let local = local.into();
Self {
imported: local.clone(),
local,
module: module.into(),
type_info: TypeInfo::unknown(),
is_type_only: false,
}
}
pub fn with_imported(mut self, imported: impl Into<String>) -> Self {
self.imported = imported.into();
self
}
pub fn with_type(mut self, type_info: TypeInfo) -> Self {
self.type_info = type_info;
self
}
pub fn type_only(mut self) -> Self {
self.is_type_only = true;
self
}
}
#[derive(Debug, Clone)]
pub struct Prop {
pub name: String,
pub type_info: TypeInfo,
pub required: bool,
pub default: Option<String>,
pub validator: Option<String>,
}
impl Prop {
pub fn new(name: impl Into<String>, type_info: TypeInfo) -> Self {
Self {
name: name.into(),
type_info,
required: false,
default: None,
validator: None,
}
}
pub fn required(mut self) -> Self {
self.required = true;
self
}
pub fn with_default(mut self, default: impl Into<String>) -> Self {
self.default = Some(default.into());
self
}
}
#[derive(Debug, Clone)]
pub struct Emit {
pub name: String,
pub payload_type: Option<TypeInfo>,
}
impl Emit {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
payload_type: None,
}
}
pub fn with_payload(mut self, type_info: TypeInfo) -> Self {
self.payload_type = Some(type_info);
self
}
}
#[derive(Debug, Clone)]
pub struct Slot {
pub name: String,
pub props_type: Option<TypeInfo>,
}
impl Slot {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
props_type: None,
}
}
pub fn default_slot() -> Self {
Self::new("")
}
pub fn with_props(mut self, type_info: TypeInfo) -> Self {
self.props_type = Some(type_info);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::TypeKind;
#[test]
fn test_type_context() {
let mut ctx = TypeContext::new();
ctx.add_binding(
"count",
Binding::new(
"count",
TypeInfo::new("Ref<number>", TypeKind::Ref),
BindingKind::Ref,
),
);
assert!(ctx.has_binding("count"));
assert!(!ctx.has_binding("unknown"));
}
#[test]
fn test_binding() {
let binding = Binding::new("foo", TypeInfo::string(), BindingKind::Const).with_offset(100);
assert_eq!(binding.name, "foo");
assert_eq!(binding.source_offset, Some(100));
}
#[test]
fn test_prop() {
let prop = Prop::new("message", TypeInfo::string())
.required()
.with_default("\"hello\"");
assert!(prop.required);
assert_eq!(prop.default, Some("\"hello\"".to_string()));
}
}