vize_musea 0.710.0

Musea - Component gallery and documentation for Vize Vue components
Documentation
use super::parse_art;
use crate::types::{ArtParseError, ArtParseOptions, ArtStatus};
use vize_l0::Allocator;

#[test]
fn test_parse_simple_art() {
    let allocator = Allocator::new();
    let source = r#"
<art title="Button" component="./Button.vue">
  <variant name="Primary" default>
    <Button>Click me</Button>
  </variant>
</art>

<script setup lang="ts">
import Button from "./Button.vue";
</script>
"#;

    let desc = parse_art(&allocator, source, ArtParseOptions::default()).unwrap();
    assert_eq!(desc.metadata.title, "Button");
    assert_eq!(desc.metadata.component, Some("./Button.vue"));
    assert_eq!(desc.variants.len(), 1);
    assert_eq!(desc.variants[0].name, "Primary");
    assert!(desc.variants[0].is_default);
    let script = desc.script_setup.expect("script setup");
    assert_eq!(
        (script.content, script.lang, script.setup),
        (r#"import Button from "./Button.vue";"#, Some("ts"), true)
    );
}

#[test]
fn test_parse_multiple_variants() {
    let allocator = Allocator::new();
    let source = r#"
<art title="Button">
  <variant name="Primary" default>
    <Button variant="primary">Click</Button>
  </variant>
  <variant name="Secondary">
    <Button variant="secondary">Click</Button>
  </variant>
  <variant name="Disabled">
    <Button disabled>Click</Button>
  </variant>
</art>
"#;

    let desc = parse_art(&allocator, source, ArtParseOptions::default()).unwrap();
    let names: std::vec::Vec<_> = desc.variants.iter().map(|v| v.name).collect();
    assert_eq!(names, ["Primary", "Secondary", "Disabled"]);
}

#[test]
fn test_parse_define_art_metadata() {
    let allocator = Allocator::new();
    let source = r#"
<script setup lang="ts">
import Button from "./Button.vue";

defineArt(Button, {
  title: "Button",
  description: "A button component",
  category: "Components",
  tags: ["button", "ui"],
  status: "draft",
  order: 2,
});
</script>

<art>
  <variant name="Primary" default>
    <Button>Click</Button>
  </variant>
</art>
"#;

    let desc = parse_art(&allocator, source, ArtParseOptions::default()).unwrap();

    assert_eq!(desc.metadata.title, "Button");
    assert_eq!(desc.metadata.component, Some("./Button.vue"));
    assert_eq!(desc.metadata.description, Some("A button component"));
    assert_eq!(desc.metadata.category, Some("Components"));
    assert_eq!(desc.metadata.tags.as_slice(), ["button", "ui"]);
    assert_eq!(desc.metadata.status, ArtStatus::Draft);
    assert_eq!(desc.metadata.order, Some(2));
}

#[test]
fn test_parse_define_art_source_literal_metadata() {
    let allocator = Allocator::new();
    let source = r#"
<script setup lang="ts">
defineArt("./base-button.vue", {
  title: "Base Button",
  category: "Components",
});
</script>

<art>
  <variant name="Primary" default>
    <BaseButton>Click</BaseButton>
  </variant>
</art>
"#;

    let desc = parse_art(&allocator, source, ArtParseOptions::default()).unwrap();

    assert_eq!(desc.metadata.title, "Base Button");
    assert_eq!(desc.metadata.component, Some("./base-button.vue"));
    assert_eq!(desc.metadata.category, Some("Components"));
}

#[test]
fn test_missing_title_error() {
    let allocator = Allocator::new();
    let source = r#"<art><variant name="Test"></variant></art>"#;
    let result = parse_art(&allocator, source, ArtParseOptions::default());
    assert!(matches!(result, Err(ArtParseError::MissingTitle)));
}

#[test]
fn test_no_art_block_error() {
    let allocator = Allocator::new();
    let source = r#"<template><div>Hello</div></template>"#;
    let result = parse_art(&allocator, source, ArtParseOptions::default());
    assert!(matches!(result, Err(ArtParseError::NoArtBlock)));
}

#[test]
fn container_errors_surface_as_parse_errors() {
    let allocator = Allocator::new();
    let source = "<art title=\"A\"></art>\n<script setup>\n</script>\n<script setup>\n</script>\n";
    let Err(ArtParseError::ParseError { line, message }) =
        parse_art(&allocator, source, ArtParseOptions::default())
    else {
        panic!("expected the SFC splitter's duplicate-block error");
    };
    assert_eq!(
        (line, message.as_str()),
        (4, "SFC can only contain one <script setup> block")
    );
}

#[test]
fn every_slice_borrows_the_source_at_file_absolute_offsets() {
    let allocator = Allocator::new();
    let source = "<script setup lang=\"ts\">\nconst a = 1\n</script>\n<art title=\"T\">\n  <variant name=\"V\">\n    <b>x</b>\n  </variant>\n</art>\n<style scoped lang=\"css\">\n.a {}\n</style>\n";
    let desc = parse_art(&allocator, source, ArtParseOptions::default()).unwrap();
    let at = |slice: &str| slice.as_ptr() as usize - source.as_ptr() as usize;
    let variant = &desc.variants[0];
    let loc = variant.loc.expect("variant loc");
    assert_eq!(
        (at(variant.template), variant.template, at(variant.name)),
        (
            source.find("<b>").unwrap(),
            "<b>x</b>",
            source.find("V\"").unwrap()
        )
    );
    assert_eq!(
        (loc.start, loc.end, loc.start_line, loc.start_column),
        (
            source.find("<variant").unwrap() as u32,
            (source.find("</variant>").unwrap() + 10) as u32,
            5,
            2
        )
    );
    assert_eq!(at(desc.metadata.title), source.find("T\"").unwrap());
    let style = &desc.styles[0];
    let style_loc = style.loc.expect("style loc");
    assert_eq!(
        (style.content, style.lang, style.scoped),
        (".a {}", Some("css"), true)
    );
    assert_eq!(
        (style_loc.start, style_loc.end, style_loc.start_line),
        (
            source.find("<style").unwrap() as u32,
            source.len() as u32 - 1,
            9
        )
    );
}