vize_l2 0.486.0

L2 - the Davinci semantic IR (codename Disegno): the neutral op family every input dialect lowers into
Documentation
use vize_l0::{
    Allocator,
    config::{VueDialect, VueVersion},
};
use vize_l1::{
    SurfaceParseOptions,
    container::{
        Vue,
        vue::{DescriptorObservation, DescriptorOptions},
    },
    embed::{
        EmbedSource,
        syntax::{ProgramOptions, parse_program_once},
    },
    markup::NativeTemplateComponent,
};
use vize_l2::{
    file::{DeclarationKind, Namespace},
    lang::js::{
        FileProducer, NativeSetupIssueKind, NativeTemplateIssueKind, NativeTemplateOwner,
        ProgramInput, ProgramScope, SetupIssueKind, VueSetup,
    },
};

fn descriptor<'a>(arena: &'a Allocator, source: &'a str) -> DescriptorObservation<'a> {
    Vue.observe_descriptor(
        arena,
        source,
        DescriptorOptions {
            version: VueVersion::V3,
            dialect: VueDialect::Vue,
            template: SurfaceParseOptions::default(),
        },
    )
}

#[test]
fn a_complete_optional_function_never_grants_primitive_setup_or_ordinary_eligibility() {
    let arena = Allocator::default();
    let source = "<template>{{ primitive }}</template><script setup lang=ts>/* original 🌸 */function f(value?:number){return value;}const primitive=1;</script>";
    let observation = descriptor(&arena, source);
    let admitted = observation.admitted().unwrap();
    let script = admitted.setup().unwrap();
    let syntax = parse_program_once(
        &arena,
        EmbedSource::authored(source, script.block().span()).unwrap(),
        ProgramOptions::module(script.lang()),
    );
    let original = syntax.admitted_program().unwrap();
    let body = original.program().body.as_ptr();
    let mut producer = FileProducer::new(&arena, source).unwrap();
    producer
        .program(
            ProgramInput::checked(original, script.block(), script.container_index()).unwrap(),
            ProgramScope::Nested,
        )
        .unwrap();
    let file = producer.finish().unwrap();
    assert!(file.is_complete(), "{:?}", file.issues());
    assert_eq!(file.scopes().len(), 3);
    let parameter = file
        .lookup(file.scopes()[2].id, "value", Namespace::Value)
        .unwrap();
    assert_eq!(
        parameter.declaration().unwrap().kind,
        DeclarationKind::Parameter
    );
    assert_eq!(parameter.declaration().unwrap().span.slice(source), "value");
    assert!(
        matches!(VueSetup::checked(&file, script, syntax.admitted_program().unwrap()),
        Err(issue) if issue.kind == SetupIssueKind::UnsupportedSyntax)
    );
    assert!(file.ordinary_empty_script().is_none());
    assert_eq!(syntax.program().unwrap().body.as_ptr(), body);
    assert_eq!(syntax.comments().count(), 1);
    assert!(core::ptr::eq(syntax.source().authored_root(), source));
}

#[test]
fn optional_setup_refuses_before_consuming_any_original_template_child() {
    let arena = Allocator::default();
    let source = "<template>{{ primitive }}</template><script setup lang=ts>/* original */function f(value?:number){return value;}const primitive=1;</script>";
    let observation = descriptor(&arena, source);
    let selected = NativeTemplateComponent::parse_in(&arena, observation.admitted().unwrap())
        .unwrap()
        .unwrap();
    let mut owner =
        NativeTemplateOwner::new(selected).unwrap_or_else(|_| panic!("original selected owner"));
    owner.parse_setup_program().unwrap();
    let syntax = owner.retained_setup().unwrap();
    let body = syntax.program().unwrap().body.as_ptr();
    let span = syntax.source().span();
    assert_eq!(syntax.comments().count(), 1);
    assert!(
        matches!(owner.begin_setup(), Err(issue) if issue.span == span && issue.kind == NativeTemplateIssueKind::SetupPolicy(NativeSetupIssueKind::UnsupportedSyntax))
    );
    let output = Box::new(owner.finish());
    assert!(output.view().is_err());
    let syntax = output.retained_setup().unwrap();
    assert_eq!(syntax.program().unwrap().body.as_ptr(), body);
    assert_eq!(syntax.source().span(), span);
    assert!(core::ptr::eq(syntax.source().authored_root(), source));
    let file = output.file().unwrap();
    assert!(file.native_interpolations().is_empty());
    assert!(file.bindings().any(|binding| {
        binding.declaration().is_some_and(|declaration| {
            declaration.kind == DeclarationKind::Parameter
                && declaration.span.slice(source) == "value"
        })
    }));
}