vize_l1 0.544.0

L1 - the lossless Vue-template surface tree (codename Sinopia, Davinci P2-7)
Documentation
use super::*;
use crate::container::vue::{DescriptorOptions, Vue};
use crate::markup::SurfaceParseOptions;
use vize_l0::Allocator;
use vize_l0::config::{VueDialect, VueVersion};

mod custody;
mod refusals;

fn options() -> DescriptorOptions {
    DescriptorOptions {
        version: VueVersion::V3,
        dialect: VueDialect::Vue,
        template: SurfaceParseOptions::default(),
    }
}

fn utf16(source: &str, offset: u32) -> (usize, usize) {
    let prefix = source.get(..offset as usize).unwrap();
    (
        prefix.bytes().filter(|byte| *byte == b'\n').count(),
        prefix.rsplit('\n').next().unwrap().encode_utf16().count(),
    )
}

#[test]
fn original_3471_outer_names_keep_complete_source_script_role_and_order() {
    let source = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../../crates/vize_maestro/tests/fixtures/native-linked-history-3471.vue"
    ));
    assert_eq!(
        source,
        "<script setup lang=\"ts\">\nconst count = 1\n</script>\n\n<template>\n  <div class=\"a\">\n    <div class=\"b\">{{ count }}</div>\n  </div>\n  <div class=\"c\" />\n</template>\n"
    );
    let arena = Allocator::default();
    let owner = Vue.observe_descriptor(&arena, source, options());
    let admitted = owner.admitted().unwrap();
    let template = admitted.template().unwrap();
    let names = template.frame_names().unwrap();
    assert_eq!(names.opening(), Span::new(53, 61));
    assert_eq!(names.closing(), Span::new(149, 157));
    assert_eq!(utf16(source, names.opening().start), (4, 1));
    assert_eq!(utf16(source, names.opening().end), (4, 9));
    assert_eq!(utf16(source, names.closing().start), (9, 2));
    assert_eq!(utf16(source, names.closing().end), (9, 10));
    assert_eq!(names.source_block().source().as_ptr(), source.as_ptr());
    assert_eq!(names.container_index(), 1);
    assert!(names.accepts(&template));
    assert!(names.accepts(&names.template()));
    assert_eq!(admitted.setup().unwrap().container_index(), 0);
    assert_eq!(admitted.setup().unwrap().lang(), crate::embed::Lang::Ts);
    assert!(!template.block().contains_block_span(names.opening()));
    assert!(!template.block().contains_block_span(names.closing()));
}

#[test]
fn original_empty_template_still_has_two_nonempty_frame_names() {
    let source = "<template></template>";
    let arena = Allocator::default();
    let owner = Vue.observe_descriptor(&arena, source, options());
    let template = owner.admitted().unwrap().template().unwrap();
    let names = template.frame_names().unwrap();
    assert_eq!(template.block().span(), Span::new(10, 10));
    assert_eq!(names.opening(), Span::new(1, 9));
    assert_eq!(names.closing(), Span::new(12, 20));
    assert_eq!(names.source_block().span(), Span::new(0, 21));
}

#[test]
fn original_unicode_crlf_nonzero_template_uses_whole_root_utf8_and_utf16() {
    let source = "<!-- 😀日本語 -->\r\n<script setup lang='ts'>const x=1</script>\r\n<template lang=html>\r\n<p>😀</p>\r\n</template \t>\r\n<style>.x{}</style>";
    let arena = Allocator::default();
    let owner = Vue.observe_descriptor(&arena, source, options());
    let admitted = owner.admitted().unwrap();
    let template = admitted.template().unwrap();
    let names = template.frame_names().unwrap();
    assert_eq!(names.opening(), Span::new(69, 77));
    assert_eq!(names.closing(), Span::new(105, 113));
    assert_eq!(utf16(source, names.opening().start), (2, 1));
    assert_eq!(utf16(source, names.opening().end), (2, 9));
    assert_eq!(utf16(source, names.closing().start), (4, 2));
    assert_eq!(utf16(source, names.closing().end), (4, 10));
    assert_eq!(template.block().source(), "\r\n<p>😀</p>\r\n");
    assert_eq!(names.container_index(), 1);
    assert_eq!(names.source_block().start(), 0);
    assert_eq!(names.source_block().source().as_ptr(), source.as_ptr());
    assert!(names.source_block().contains_block_span(names.opening()));
    assert!(!template.block().contains_block_span(names.opening()));
    assert_eq!(admitted.setup().unwrap().lang(), crate::embed::Lang::Ts);
    assert_eq!(admitted.styles().next().unwrap().container_index(), 2);
}

#[test]
fn only_original_depth_zero_close_owns_a_nested_template_frame() {
    let source = "<template><template #x>nested</template><template/>after</template>";
    let arena = Allocator::default();
    let owner = Vue.observe_descriptor(&arena, source, options());
    let template = owner.admitted().unwrap().template().unwrap();
    let names = template.frame_names().unwrap();
    assert_eq!(names.opening(), Span::new(1, 9));
    assert_eq!(names.closing(), Span::new(58, 66));
    assert_eq!(
        template.block().source(),
        "<template #x>nested</template><template/>after"
    );
    assert_eq!(owner.container().blocks.len(), 1);
}

#[test]
fn original_comment_attribute_interpolation_and_raw_closers_never_supply_the_frame() {
    let source = "<template><!-- </template> --><p x='</template>'>x</p>{{ '</template>' }}<textarea></template></textarea></template>";
    let arena = Allocator::default();
    let owner = Vue.observe_descriptor(&arena, source, options());
    let template = owner.admitted().unwrap().template().unwrap();
    let names = template.frame_names().unwrap();
    assert_eq!(names.closing(), Span::new(107, 115));
    assert_eq!(owner.container().blocks.len(), 1);
    assert!(template.block().source().ends_with("</textarea>"));
}

#[test]
fn original_ascii_closing_case_and_post_name_gap_are_retained_without_normalization() {
    let arena = Allocator::default();
    for source in ["<template></TeMPLATE >", "<template></template \t\r\n>"] {
        let owner = Vue.observe_descriptor(&arena, source, options());
        let names = owner
            .admitted()
            .unwrap()
            .template()
            .unwrap()
            .frame_names()
            .unwrap();
        assert_eq!(names.opening(), Span::new(1, 9));
        assert_eq!(names.closing(), Span::new(12, 20));
        let closing = source.get(12..20).unwrap();
        assert_eq!(
            closing,
            if source.contains("TeMPLATE") {
                "TeMPLATE"
            } else {
                "template"
            }
        );
        assert_eq!(source.get(1..9), Some("template"));
    }
}