use crate::file::build::Facts;
use crate::file::vue::{ExposureIssueKind, VueExposure};
use crate::file::{BindingRef, FileArtifact, ScopeId, ScriptUnitId};
use oxc_ast::ast::Program;
use oxc_parser::AdmittedProgram;
use vize_l0::{SourceBlock, Span};
use vize_l1::container::vue::ScriptView;
use vize_l1::embed::Lang;
pub(crate) fn initial(program: &Program<'_>) -> bool {
let profile = program.source_type;
profile.is_module()
&& !profile.is_unambiguous()
&& !profile.is_typescript()
&& !profile.is_jsx()
&& program.directives.is_empty()
&& program.hashbang.is_none()
}
pub(super) fn reject(facts: &mut Facts<'_>, id: ScriptUnitId) {
if let Some(unit) = facts.units.last_mut()
&& unit.id == id
{
unit.origin.setup_eligible = false;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SetupIssueKind {
Exposure(ExposureIssueKind),
Profile,
Scope,
UnsupportedSyntax,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SetupIssue {
pub span: Span,
pub kind: SetupIssueKind,
}
pub struct VueSetup<'owner, 'descriptor, 'program, 'arena> {
exposure: VueExposure<'owner, 'descriptor, 'program, 'arena>,
}
impl<'owner, 'descriptor, 'program, 'arena> VueSetup<'owner, 'descriptor, 'program, 'arena> {
pub fn checked(
file: &'owner FileArtifact<'arena>,
script: ScriptView<'descriptor, 'arena>,
program: AdmittedProgram<'program, 'arena>,
) -> Result<Self, SetupIssue> {
let span = script.block().span();
let reject = |kind| SetupIssue { span, kind };
let exposure = VueExposure::checked(file, script, program)
.map_err(|issue| reject(SetupIssueKind::Exposure(issue.kind)))?;
if exposure.script().lang() != Lang::Js {
return Err(reject(SetupIssueKind::Profile));
}
let unit = file
.units()
.iter()
.find(|unit| unit.id == exposure.unit())
.ok_or_else(|| reject(SetupIssueKind::Scope))?;
if unit.scope.index() == 0
|| !file
.scopes()
.get(unit.scope.index() as usize)
.is_some_and(|scope| {
scope.id == unit.scope && scope.parent == Some(ScopeId(0)) && scope.span == span
})
{
return Err(reject(SetupIssueKind::Scope));
}
if !unit.origin.setup_eligible {
return Err(reject(SetupIssueKind::UnsupportedSyntax));
}
Ok(Self { exposure })
}
#[must_use]
pub fn exposure(&self) -> &VueExposure<'owner, 'descriptor, 'program, 'arena> {
&self.exposure
}
#[must_use]
pub fn source(&self) -> SourceBlock<'arena> {
self.exposure.script().block()
}
pub fn bindings(&self) -> impl Iterator<Item = BindingRef<'owner, 'arena>> + '_ {
self.exposure
.file()
.bindings()
.filter(|binding| self.exposure.binding(*binding).is_ok())
}
}